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 }
  • 相关阅读:
    Linux kill -9 和 kill -15 的区别
    redis 学习笔记之(五)redis-cli 命令
    专题(十四)awk
    Linux 学习笔记之(十一)SSH
    Linux 学习笔记之(十)查看文件
    rust 读写文件
    rust 显示本机ip
    rust error: linking with `link.exe` failed: exit code: 1181(未解决)
    Building a Concurrent Web Server with Async Rust
    Asynchronous Programming in Rust
  • 原文地址:https://www.cnblogs.com/fu3638/p/7887802.html
Copyright © 2011-2022 走看看