hdu 4411(最小费用流)

来源:互联网 发布:linux能运行exe文件吗 编辑:程序博客网 时间:2024/06/03 21:43

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

思路:这道题建图比较难想,首先是建立超级源点和超级汇点,那么由于有K个警察,于是vs与0连边,容量为k,费用为0,因为这K个警察不一定都出去,也就是不一定是最大流,于是0和vt连边,容量为k,费用为0。然后就是拆点建图了:

(1):0到i连边,容量为1,费用0到i的最短路,表示去抓城市i的小偷。

(2):从i到i+n,容量为1,费用为-1000000(很小的负权),这样可以保证每个城市都能遍历到。

(3):对于城市i,j,(i<j),连边(i+n,j),容量为1,费用为i到j的最短路,表示抓完城市i的小偷再去抓城市j的小偷。

  1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<algorithm>  5 #include<queue>  6 using namespace std;  7 #define MAXN 222  8 #define MAXM 4444444  9 #define inf 1<<30 10  11 struct Edge{ 12     int v,cap,cost,next; 13 }edge[MAXM]; 14  15 int vs,vt,NE,n,m,k; 16 int head[MAXN]; 17  18 void Insert(int u,int v,int cap,int cost) 19 { 20     edge[NE].v=v; 21     edge[NE].cap=cap; 22     edge[NE].cost=cost; 23     edge[NE].next=head[u]; 24     head[u]=NE++; 25  26     edge[NE].v=u; 27     edge[NE].cap=0; 28     edge[NE].cost=-cost; 29     edge[NE].next=head[v]; 30     head[v]=NE++; 31 } 32  33 int dist[MAXN],pre[MAXN],cur[MAXN]; 34 bool mark[MAXN]; 35 bool spfa(int vs,int vt) 36 { 37     memset(mark,false,sizeof(mark)); 38     fill(dist,dist+MAXN-1,inf); 39     dist[vs]=0; 40     queue<int>que; 41     que.push(vs); 42     while(!que.empty()){ 43         int u=que.front(); 44         que.pop(); 45         mark[u]=false; 46         for(int i=head[u];i!=-1;i=edge[i].next){ 47             int v=edge[i].v,cost=edge[i].cost; 48             if(edge[i].cap>0&&dist[u]+cost<dist[v]){ 49                 dist[v]=dist[u]+cost; 50                 pre[v]=u; 51                 cur[v]=i; 52                 if(!mark[v]){ 53                     mark[v]=true; 54                     que.push(v); 55                 } 56             } 57         } 58     } 59     return dist[vt]<inf; 60 } 61  62 int MinCostFlow(int vs,int vt) 63 { 64     int flow=0,cost=0; 65     while(spfa(vs,vt)){ 66         int aug=inf; 67         for(int u=vt;u!=vs;u=pre[u]){ 68             aug=min(aug,edge[cur[u]].cap); 69         } 70         flow+=aug,cost+=dist[vt]*aug; 71         for(int u=vt;u!=vs;u=pre[u]){ 72             edge[cur[u]].cap-=aug; 73             edge[cur[u]^1].cap+=aug; 74         } 75     } 76     return cost; 77 } 78  79 int map[MAXN][MAXN]; 80 void floyd() 81 { 82     for(int k=0;k<=n;k++) 83         for(int i=0;i<=n;i++) 84             for(int j=0;j<=n;j++) 85                 if(map[i][k]<inf&&map[k][j]<inf&&map[i][k]+map[k][j]<map[i][j]) 86                     map[i][j]=map[i][k]+map[k][j]; 87 } 88  89 int main() 90 { 91     int u,v,w; 92     while(~scanf("%d%d%d",&n,&m,&k)){ 93         if(n==0&&m==0&&k==0)break; 94         NE=0; 95         vs=2*n+1,vt=2*n+2; 96         memset(head,-1,sizeof(head)); 97         for(int i=0;i<=n;i++) 98             for(int j=0;j<=n;j++) 99                 map[i][j]=(i==j)?0:inf;100         while(m--){101             scanf("%d%d%d",&u,&v,&w);102             map[u][v]=map[v][u]=min(map[u][v],w);103         }104         floyd();105         Insert(vs,0,k,0);106         Insert(0,vt,k,0);107         for(int i=1;i<=n;i++){108             Insert(0,i,1,map[0][i]);//0到各点109             Insert(i,i+n,1,-1000000);//每个城市拆点110             Insert(i+n,vt,1,map[0][i]);//各点到汇点,表示回到0111         }112         for(int i=1;i<=n;i++){113             for(int j=i+1;j<=n;j++){114                 Insert(i+n,j,1,map[i][j]);115             }116         }117         printf("%d\n",MinCostFlow(vs,vt)+1000000*n);118     }119     return 0;120 }
View Code

 

0 0