hdu 4411(最小费用流)

题目链接: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]);//各点到汇点,表示回到0

111         }

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

 

你可能感兴趣的:(HDU)