HDU 4370 0 or 1 最短路 + 思维

一、内容

 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;
}
发布了414 篇原创文章 · 获赞 380 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104216564