hdu 4370 0 or 1 (最短路 // 01 规划 2012 Multi-University Training Contest 8 )
http://acm.hdu.edu.cn/showproblem.php?pid=4370
题解: http://page.renren.com/601081183/note/866168965
好一道转换思维的题啊,由一道,让人 不知如何下手的题,转换为了 最短路,问题,经典。。。。
我们没有想到啊,看了题解才知道,,思维有点局限啊。。。。
1001 (已更新)
显然,题目给的是一个0/1规划模型。解题的关键在于如何看出这个模型的本质。
3个条件明显在刻画未知数之间的关系,从图论的角度思考问题,容易得到下面3个结论:
1.X12+X13+...X1n=1 于是1号节点的出度为1
2..X1n+X2n+...Xn-1n=1 于是n号节点的入度为1
3.∑Xki =∑Xij 于是2~n-1号节点的入度必须等于出度
于是3个条件等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。
最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。
以上情况设为A
非常非常非常非常非常非常非常非常抱歉,简单路径只是充分条件,但不必要。(对造成困扰的队伍深表歉意)
漏了如下的情况B:
从1出发,走一个环(至少经过1个点,即不能是自环),回到1;从n出发,走一个环(同理),回到n。
容易验证,这是符合题目条件的。且A || B为该题要求的充要条件。
由于边权非负,于是两个环对应着两个简单环。
因此我们可以从1出发,找一个最小花费环,记代价为c1,再从n出发,找一个最小花费环,记代价为c2。(只需在最短路算法更新权值时多加一条记录即可:if(i==S) cir=min(cir,dis[u]+g[u][i]))
故最终答案为min(path,c1+c2)
View Code
1 #include<stdio.h>
2 #include<iostream>
3 #include<algorithm>
4 #include<cstring>
5 #include<cmath>
6 #include<queue>
7 #include<set>
8 #include<map>
9 #define Min(a,b) a>b?b:a
10 #define Max(a,b) a>b?a:b
11 #define CL(a,num) memset(a,num,sizeof(a));
12 #define inf 99999999
13 #define maxn 500
14 #define mod 100000007
15 #define eps 1e-6
16 #define ll long long
17 #define M 15520
18 using namespace std;
19 int n,mat[maxn][maxn],vis[maxn],dis[maxn];
20 void SPFA(int x)
21 {
22 int i ;
23 queue<int>que;
24 CL(vis,0);
25 for( i = 1; i <= n;++i)
26 {
27 if(i == x)
28 {
29 dis[i] = inf;
30 }
31 else
32 {
33 dis[i] = mat[x][i];
34 vis[i] = 1;
35 que.push(i);
36 }
37 }
38 while(!que.empty())
39 {
40 int u = que.front(); que.pop();
41 vis[u] = 0;
42
43 for( i =1; i <= n ;++i)
44 {
45 if(dis[i] > dis[u] + mat[u][i])
46 {
47 dis[i] = dis[u] + mat[u][i] ;
48 if(!vis[i])
49 {
50 que.push(i);
51 vis[i] = 1 ;
52 }
53
54 }
55 }
56
57 }
58 }
59 int main()
60 {
61 int i,j;
62 while(scanf("%d",&n)!=EOF){
63
64 for( i = 1; i <=n; ++i)
65 for( j = 1; j <= n;++j)
66 scanf("%d",&mat[i][j]);
67
68
69 SPFA(1);
70 int ans = dis[n];
71 int c1 = dis[1] ;
72 SPFA(n);
73 int c2 = dis[n] ;
74 ans = min(ans,c1+c2);
75 printf("%d\n",ans);
76
77
78
79
80 }
81 }
2 #include<iostream>
3 #include<algorithm>
4 #include<cstring>
5 #include<cmath>
6 #include<queue>
7 #include<set>
8 #include<map>
9 #define Min(a,b) a>b?b:a
10 #define Max(a,b) a>b?a:b
11 #define CL(a,num) memset(a,num,sizeof(a));
12 #define inf 99999999
13 #define maxn 500
14 #define mod 100000007
15 #define eps 1e-6
16 #define ll long long
17 #define M 15520
18 using namespace std;
19 int n,mat[maxn][maxn],vis[maxn],dis[maxn];
20 void SPFA(int x)
21 {
22 int i ;
23 queue<int>que;
24 CL(vis,0);
25 for( i = 1; i <= n;++i)
26 {
27 if(i == x)
28 {
29 dis[i] = inf;
30 }
31 else
32 {
33 dis[i] = mat[x][i];
34 vis[i] = 1;
35 que.push(i);
36 }
37 }
38 while(!que.empty())
39 {
40 int u = que.front(); que.pop();
41 vis[u] = 0;
42
43 for( i =1; i <= n ;++i)
44 {
45 if(dis[i] > dis[u] + mat[u][i])
46 {
47 dis[i] = dis[u] + mat[u][i] ;
48 if(!vis[i])
49 {
50 que.push(i);
51 vis[i] = 1 ;
52 }
53
54 }
55 }
56
57 }
58 }
59 int main()
60 {
61 int i,j;
62 while(scanf("%d",&n)!=EOF){
63
64 for( i = 1; i <=n; ++i)
65 for( j = 1; j <= n;++j)
66 scanf("%d",&mat[i][j]);
67
68
69 SPFA(1);
70 int ans = dis[n];
71 int c1 = dis[1] ;
72 SPFA(n);
73 int c2 = dis[n] ;
74 ans = min(ans,c1+c2);
75 printf("%d\n",ans);
76
77
78
79
80 }
81 }