hdu 4411 2012杭州赛区网络赛 最小费用最大流 ***
题意: 有 n+1 个城市编号 0..n,有 m 条无向边,在 0 城市有个警察总部,最多可以派出 k 个逮捕队伍,在1..n 每个城市有一个犯罪团伙,
每个逮捕队伍在每个城市可以选择抓或不抓,如果抓了 第 i 个城市的犯罪团伙,第 i-1 个城市的犯罪团伙就知道了消息 ,如果第 i-1 的犯罪
团伙之前没有被抓,任务就失败,问要抓到所有的犯罪团伙,派出的队伍需要走的最短路是多少。
分析: 最小费用最大流,需要注意的地方在于怎么去保证每个每个城市的团伙仅仅被抓一次,且在抓他之前,第i-1城市的团伙已经被抓。
方法是把拆点后的城市 i 和 i`之间的费用要设成一个很小的负值,这样可以保证该城市一定可以被访问到,
还有一点要注意的是派出的k个队可能有些队是不执行任务的,
方法是在 0 节点和 汇点之间连一条费用为0,容量为k的边
具体建图:
源点 s=2*n+1,
汇点 t=2*n+2,
每个城市拆成两个点 i 和 i+n,费用为 -100000,容量为 1
在源点和 0 之间连一条费用为 0 容量为 k 的边
在 0 和 城市 1..n之间连一条费用为 0 到 i 最短路容量为 1 的边(表示出发)
在 城市 n+1..n+n到汇点之间连一条费用为 0 到 i 最短路容量为 1 的边(表示回到总部)
在 城市 n+i..n+n 和 j(j>i)直间连一条费用为城市 i 到 j 最短路距离容量为 1 的边
求最小费用流。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const int INF=0x3f3f3f3f; 11 const double eps=1e-5; 12 typedef long long ll; 13 #define cl(a) memset(a,0,sizeof(a)) 14 #define ts printf("*****\n"); 15 int n,m,tt; 16 /*最小费用大流,求只需要取相反数结果即可。 17 点的总数为 N,点的编号 0~N -1*/ 18 const int MAXN = 222; 19 const int MAXM = 4444444; 20 struct Edge 21 { 22 int to,next,cap,flow,cost; 23 }edge[MAXM]; 24 int head[MAXN],tol; 25 int pre[MAXN],dis[MAXN]; 26 bool vis[MAXN]; 27 int N;//节点总个数,节点编号从0~N-1 28 void init(int n) 29 { 30 N = n; 31 tol = 0; 32 memset(head,-1,sizeof(head)); 33 } 34 void addedge(int u,int v,int cap,int cost) 35 { 36 edge[tol].to = v; 37 edge[tol].cap = cap; 38 edge[tol].cost = cost; 39 edge[tol].flow = 0; 40 edge[tol].next = head[u]; 41 head[u] = tol++; 42 edge[tol].to = u; 43 edge[tol].cap = 0; 44 edge[tol].cost = -cost; 45 edge[tol].flow = 0; 46 edge[tol].next = head[v]; 47 head[v] = tol++; 48 } 49 bool spfa(int s,int t) 50 { 51 queue<int>q; 52 for(int i = 0;i < N;i++) 53 { 54 dis[i] = INF; 55 vis[i] = false; 56 pre[i] = -1; 57 } 58 dis[s] = 0; 59 vis[s] = true; 60 q.push(s); 61 while(!q.empty()) 62 { 63 int u = q.front(); 64 q.pop(); 65 vis[u] = false; 66 for(int i = head[u]; i != -1;i = edge[i].next) 67 { 68 int v = edge[i].to; 69 if(edge[i].cap > edge[i].flow && 70 dis[v] > dis[u] + edge[i].cost ) 71 { 72 dis[v] = dis[u] + edge[i].cost; 73 pre[v] = i; 74 if(!vis[v]) 75 { 76 vis[v] = true; 77 q.push(v); 78 } 79 } 80 } 81 } 82 if(pre[t] == -1)return false; 83 else return true; 84 } 85 //返回的是最大流,cost存的是最小费用 86 int minCostMaxflow(int s,int t) 87 { 88 int flow = 0; 89 int cost = 0; 90 while(spfa(s,t)) 91 { 92 int Min = INF; 93 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 94 { 95 if(Min > edge[i].cap - edge[i].flow) 96 Min = edge[i].cap - edge[i].flow; 97 } 98 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 99 { 100 edge[i].flow += Min; 101 edge[i^1].flow -= Min; 102 cost += edge[i].cost * Min; 103 } 104 flow += Min; 105 } 106 return cost; 107 } 108 int c[MAXN][MAXN]; 109 void floyd(){ 110 for(int k=0;k<=n;++k){ 111 for(int i=0;i<=n;++i){ 112 for(int j=0;j<=n;++j){ 113 c[i][j]=min(c[i][j],c[i][k]+c[k][j]); 114 } 115 } 116 } 117 } 118 int main() 119 { 120 int i,j,k,ca=1; 121 #ifndef ONLINE_JUDGE 122 freopen("1.in","r",stdin); 123 #endif 124 while(~scanf("%d%d%d",&n,&m,&k)&&n&&m&&k) 125 { 126 init(2*n+3); 127 for(i=0;i<=n;i++) 128 for(j=0;j<=n;j++) 129 { 130 c[i][j]=(i==j)?0:INF; 131 } 132 int st=2*n+1; 133 int ed=2*n+2; 134 addedge(st,0,k,0); 135 addedge(0,ed,k,0); 136 while(m--) 137 { 138 int u,v,w; 139 scanf("%d%d%d",&u,&v,&w); 140 c[u][v]=c[v][u]=min(c[u][v],w); 141 } 142 floyd(); 143 for(i=1;i<=n;i++) 144 { 145 addedge(0,i,1,c[0][i]); 146 addedge(i,i+n,1,-100000); 147 addedge(i+n,ed,1,c[0][i]); 148 } 149 for(i=1;i<=n;i++) 150 { 151 for(j=i+1;j<=n;j++) 152 { 153 addedge(i+n,j,1,c[i][j]); 154 } 155 } 156 printf("%d\n",minCostMaxflow(st,ed)+100000*n); 157 } 158 }