zoukankan      html  css  js  c++  java
  • HDU 4370 0 or 1(spfa+思维建图+计算最小环)

    题目链接: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
    ",ans);
    57     }
    58     return 0;
    59 }
  • 相关阅读:
    LeetCode Subsets II
    LeetCode Rotate Image
    LeetCode Palidrome Number
    LeetCode Generate Parentheses
    LeetCode Maximum Subarray
    LeetCode Set Matrix Zeroes
    LeetCode Remove Nth Node From End of List
    Linux Loop设备 使用
    Linux 文件系统大小调整
    LeetCode N-Queens II
  • 原文地址:https://www.cnblogs.com/fu3638/p/7887802.html
Copyright © 2011-2022 走看看