码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4370 0 or 1(spfa+思维建图+计算最小环)

时间:2017-11-24 01:01:20      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:stream   邻接矩阵   scanf   iostream   解题思路   using   string   star   cstring   

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4370

题目大意:有一个n*n的矩阵Cij(1<=i,j<=n),要找到矩阵Xij(i<=1,j<=n)满足以下条件:

     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). 

举个例子, 如果 n=4,上面条件等价于以下情况:
     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 

找出 ∑C ij*X ij(1<=i,j<=n)的最小值。

解题思路:这题主要是考建图的思维,看了kuangbin写的才会,下面都是照搬他博客的东西。解题的关键在于如何看出这个模型的本质。


3个条件明显在刻画未知数之间的关系,从图论的角度思考问题,容易得到下面3个结论:

     ①.X12+X13+...X1n=1 于是1号节点的出度为1

     ②..X1n+X2n+...Xn-1n=1 于是n号节点的入度为1

     ③.∑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。

故最终答案为min(spfa(1,n),spfa(1,1)+spfa(n,n))。

spfa里面计算最小环,还需要一点修改,当计算环时(dis[start]==INF且start不入队,计算所有start能到达的点并入队)。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #include<cstdio>
 6 using namespace std;
 7 const int N=3e2+5;
 8 const int INF=0x3f3f3f3f;
 9 
10 int n;
11 int cost[N][N],dis[N];
12 bool vis[N];
13 
14 int spfa(int s,int e){
15     memset(dis,0x3f,sizeof(dis));
16     memset(vis,false,sizeof(vis));
17     queue<int>q;
18     if(s==e){
19         for(int i=1;i<=n;i++){
20             if(i!=s){
21                 q.push(i);
22                 dis[i]=cost[s][i];
23                 vis[i]=true;
24             }
25         }
26     }
27     else{
28         dis[s]=0;
29         q.push(s);
30     }
31     while(!q.empty()){
32         int k=q.front();
33         q.pop();
34         vis[k]=false;
35         for(int i=1;i<=n;i++){
36             if(dis[k]+cost[k][i]<dis[i]){
37                 dis[i]=dis[k]+cost[k][i];
38                 if(!vis[i]){
39                     q.push(i);
40                     vis[i]=true;
41                 }
42             }
43         }
44     }
45     return dis[e];
46 }
47 
48 int main(){
49     while(scanf("%d",&n)!=EOF){
50         for(int i=1;i<=n;i++){
51             for(int j=1;j<=n;j++){
52                 scanf("%d",&cost[i][j]);
53             }
54         }
55         int ans=min(spfa(1,n),spfa(1,1)+spfa(n,n));
56         printf("%d\n",ans);
57     }
58     return 0;
59 }

 

HDU 4370 0 or 1(spfa+思维建图+计算最小环)

标签:stream   邻接矩阵   scanf   iostream   解题思路   using   string   star   cstring   

原文地址:http://www.cnblogs.com/fu3638/p/7887802.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!