一、内容
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.
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).
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
二、思路
-
1.X 12+X 13+…X 1n=1 第一个条件可以看作是点1有一个出度
-
2.X 1n+X 2n+…X n-1n=1 第二个条件可以看做是点n有一个入度
-
for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n). 第三个条件代表第i行的所有值=第i列的所有值,那么可以看作每个点的入度和出度必须相同。
-
2个矩阵相乘就可以看做从1点出发经过某些点最后到达n的一条路径。刚好满足1点出度为1,n入度为1,其他点出度入度相等。
-
还有一种情况也满足3个条件。 那就是自环。 从1回到1, 从n回到n. 这里n不能直接连向自己,这样不算一个入度,因为题目第二个条件不包括Xnn. 同理1点也不能自己连向自己。因为第一个条件不包含X11 所以我们至少连接一个点,最后回到1才算作子环。
-
最后比较2种情况路径最短即可。
三、代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 305, INF = 0x3f3f3f3f;
int n, cir, ans, g[N][N], d[N];
bool vis[N];
void djkstra(int s) {
memset(d, 0x3f, sizeof(d));
memset(vis, false, sizeof(vis));
d[s] = 0;
for (int i = 1; i <= n; i++) {
int t = -1;
for (int j = 1; j <= n; j++) {
if (!vis[j] && (t == -1 || d[t] > d[j])) {
t = j;
}
}
vis[t] = true;
for (int j = 1; j <= n; j++) {
d[j] = min(d[j], d[t] + g[t][j]);
//这里t不能等于起点 因为不能是起点自环
//但是1可以是自环
if (j == s && t != s) cir = min(cir, d[t] + g[t][j]);
}
}
}
int main() {
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &g[i][j]);
}
}
cir = INF;
djkstra(1);
ans = d[n]; //1-n的最短路径
int t = cir; //1的子环
cir = INF;
djkstra(n);
t += cir; //加上n的子环
printf("%d\n", min(ans, t));
}
return 0;
}