题目大意:给出一张N+1个点和M条边的带权有向图,代表有N+1个城市和M条路,在0有警察局,1-N这些城市有犯罪分子,现在给你K个条子,从0从发,要求按从小到大的顺序依次收拾掉这些犯罪分子,每个条子到达一个城市的时候,他可以收拾这里的人,也可以不收拾,但绝不能让第i+1个城市的人早与第i个城市的人被干掉,求让这些人从0出发完成任务后回到0的走过的最短路之和。
解法:这里给的K个条子可以不用完。。所以有两条边(S,0,K,0),(0,T,K,0)。然后为了保证每个点都被遍历到,需要拆点建边,并且保证这条边一定会走到(i,i',-oo,0)。对于城市1-N,从0出发最后要回到0,对应两条边(0,i,1,dis[0][i]),(i',T,1,dis[0][1])。对于城市i<j,对应一条边(i',j,1,dis[i][j])。跑最小费用流,ans+N*oo就是结果。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define maxn 210 6 #define maxm 101000 7 #define INF 1<<29 8 #define oo 1000000 9 using namespace std; 10 struct MCMF{ 11 int src,sink,e,n; 12 int first[maxn]; 13 int cap[maxm],cost[maxm],v[maxm],next[maxm]; 14 bool flag; 15 void init(){ 16 e = 0; 17 memset(first,-1,sizeof(first)); 18 } 19 20 void add_edge(int a,int b,int cc,int ww){ 21 //printf("add:%d to %d,cap = %d,cost = %d\n",a,b,cc,ww); 22 cap[e] = cc;cost[e] = ww;v[e] = b; 23 next[e] = first[a];first[a] = e++; 24 cap[e] = 0;cost[e] = -ww;v[e] = a; 25 next[e] = first[b];first[b] = e++; 26 } 27 28 int d[maxn],pre[maxn],pos[maxn]; 29 bool vis[maxn]; 30 31 bool spfa(int s,int t){ 32 memset(pre,-1,sizeof(pre)); 33 memset(vis,0,sizeof(vis)); 34 queue<int> Q; 35 for(int i = 0;i <= n;i++) d[i] = INF; 36 Q.push(s);pre[s] = s;d[s] = 0;vis[s] = 1; 37 while(!Q.empty()){ 38 int u = Q.front();Q.pop(); 39 vis[u] = 0; 40 for(int i = first[u];i != -1;i = next[i]){ 41 if(cap[i] > 0 && d[u] + cost[i] < d[v[i]]){ 42 d[v[i]] = d[u] + cost[i]; 43 pre[v[i]] = u;pos[v[i]] = i; 44 if(!vis[v[i]]) vis[v[i]] = 1,Q.push(v[i]); 45 } 46 } 47 } 48 return pre[t] != -1; 49 } 50 51 int Mincost; 52 int Maxflow; 53 54 int MinCostFlow(int s,int t,int nn){ 55 Mincost = 0,Maxflow = 0,n = nn; 56 while(spfa(s,t)){ 57 int min_f = INF; 58 for(int i = t;i != s;i = pre[i]) 59 if(cap[pos[i]] < min_f) min_f = cap[pos[i]]; 60 Mincost += d[t] * min_f; 61 Maxflow += min_f; 62 for(int i = t;i != s;i = pre[i]){ 63 cap[pos[i]] -= min_f; 64 cap[pos[i]^1] += min_f; 65 } 66 } 67 return Mincost; 68 } 69 }; 70 MCMF g; 71 int N,M,K; 72 int f[maxn][maxn]; 73 inline int min(int a,int b){ 74 return a < b ? a : b; 75 } 76 void floyd(){ 77 for(int k = 0;k <= N;k++) 78 for(int i = 0;i <= N;i++) 79 for(int j = 0;j <= N;j++) 80 if(f[i][j] > f[i][k] + f[k][j]) 81 f[i][j] = f[i][k] + f[k][j]; 82 } 83 84 int main(){ 85 while(scanf("%d%d%d",&N,&M,&K),N+M+K){ 86 for(int i = 0;i <= N;i++) 87 for(int j = 0;j <= N;j++) 88 f[i][j] = INF; 89 for(int i = 0;i < M;i++){ 90 int a,b,c; 91 scanf("%d%d%d",&a,&b,&c); 92 f[a][b] = f[b][a] = min(c,f[a][b]); 93 } 94 for(int i = 0;i <= N;i++) 95 f[i][i] = 0; 96 floyd(); 97 g.init(); 98 int S = 2*N+1,T = S+1; 99 g.add_edge(S,0,K,0);g.add_edge(0,T,K,0); 100 for(int i = 1;i <= N;i++) 101 g.add_edge(0,i,1,f[0][i]),g.add_edge(i+N,T,1,f[0][i]); 102 for(int i = 1;i <= N;i++) 103 g.add_edge(i,i+N,1,-oo); 104 for(int i = 1;i <= N;i++) 105 for(int j = i+1;j <= N;j++) 106 g.add_edge(i+N,j,1,f[i][j]); 107 int ans = g.MinCostFlow(S,T,T) + N*oo; 108 printf("%d\n",ans); 109 } 110 return 0; 111 }