Description
Given a n*n matrix C ij (1<=i,j<=n),We want to find a n*n matrix X ij (1<=i,j<=n),which is 0 or 1.
Besides,X ij meets the following conditions:
1.X 12+X 13+...X 1n=1
2.X 1n+X 2n+...X n-1n=1
3.for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n).
For example, if n=4,we can get the following equality:
X 12+X 13+X 14=1
X 14+X 24+X 34=1
X 12+X 22+X 32+X 42=X 21+X 22+X 23+X 24
X 13+X 23+X 33+X 43=X 31+X 32+X 33+X 34
Now ,we want to know the minimum of ∑C ij*X ij(1<=i,j<=n) you can get.
For sample, X 12=X 24=1,all other X ij is 0.
Besides,X ij meets the following conditions:
1.X 12+X 13+...X 1n=1
2.X 1n+X 2n+...X n-1n=1
3.for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n).
For example, if n=4,we can get the following equality:
X 12+X 13+X 14=1
X 14+X 24+X 34=1
X 12+X 22+X 32+X 42=X 21+X 22+X 23+X 24
X 13+X 23+X 33+X 43=X 31+X 32+X 33+X 34
Now ,we want to know the minimum of ∑C ij*X ij(1<=i,j<=n) you can get.
Hint
For sample, X 12=X 24=1,all other X ij is 0.
Input
The input consists of multiple test cases (less than 35 case).
For each test case ,the first line contains one integer n (1<n<=300).
The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is C ij(0<=C ij<=100000).
For each test case ,the first line contains one integer n (1<n<=300).
The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is C ij(0<=C ij<=100000).
Output
For each case, output the minimum of ∑C ij*X ij you can get.
Sample Input
4 1 2 4 10 2 0 1 1 2 2 0 5 6 3 1 2
Sample Output
3
题意: (先说直接翻译过来的)
给出nxn矩阵Ci,j 求01矩阵Xij满足
1.X 12+X 13+...X 1n=1
2.X 1n+X 2n+...X n-1n=1
3.X矩阵的第i行的和等于第i列的和
做法&思路:
是在最短路分类里的QAQ百思不得其解,先把示例画出来。
咦?有行有列,莫非是拆点了?对于示例选的边可以画出这个图:
好像X矩阵是用来控制C矩阵加边与否的耶
再编一组数据找找规律
看着怎么这么眼熟,我是不是可以从右边往左边加边啊
另一个图:
越想越觉得有道理啊,因为要求第i行和第i列的和相等,就相当于通过新加的边过渡行与列,拆点,连边,其他的边正常连接就好,交了 WA了
看讨论区 有这样一组示例 ,连接的是中间图,咦?怎么分开了,所以我们需要连一个6->5的边
这样就存在两个问题:
1.有可能1->6->5->10,怎么办?1->6 5->10赋成无穷大,不走它就得了
2.如果分成好多团怎么办?依旧只连6->5,因为中间那部分就相当于for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n)=0了
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cstdio>
using namespace std;
int n,m,x;
const long long MAXINT=0x3f3f3f3f;
const int MAXNUM=609;
long long dist[MAXNUM];
long long A[MAXNUM][MAXNUM];
void Dijkstra(int v0)
{
bool S[MAXNUM];// 判断是否已存入该点到S集合中
for(int i=1; i<=n; ++i)
{
dist[i]=A[v0][i];
// printf("%d ",dist[i]);
S[i]=false; // 初始都未用过该点
}
// dist[v0] = 0;
S[v0]=true;
for(int i=2; i<=n; i++)
{
long long mindist = MAXINT;
int u = -1;// 找出当前未使用的点j的dist[j]最小值
for(int j=1; j<=n; ++j)
if((!S[j]) && dist[j]<mindist)
{
u = j;// u保存当前邻接点中距离最小的点的号码
mindist = dist[j];
//printf("%d ",mindist);
}
S[u] = true;
for(int j=1; j<=n; j++)
if((!S[j]) && A[u][j]<MAXINT)
{
if(dist[u] + A[u][j] < dist[j]) //在通过新加入的u点路径找到离v0点更短的路径
{
dist[j] = dist[u] + A[u][j]; //更新dis //记录前驱顶点
}
}
}
return;
}
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
for(int i=1; i<=n*2; i++)
{
for(int j=1; j<=n*2; j++)
if(i-j==n) A[i][j]=0;
else A[i][j]=MAXINT;
}
for(int i=1;i<=n;i++)
for(int j=1+n;j<=n*2;j++)
scanf("%I64d",&A[i][j]);
A[1][n+1]=A[n][n+n]=MAXINT;
A[n+1][n]=0;
// A[1][1+n]=A[n][n*2]=MAXINT;
// for(int i=1;i<=2*n;i++)for(int j=1;j<=2*n;j++)printf("i=%d,j=%d,A=%d\n",i,j,A[i][j]);
n=n+n;
Dijkstra(1);
//for(int i=n/2+1;i<=n;i++)
printf("%I64d\n",dist[n]);
}
return 0;
}