标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352
题意:M年前有一个国家发生了地震。所有城市和城市之间的路都被摧毁了。现在要重建城市。
给出一个N表示共有N个城市,M表示大地震发生在M年前,K表示每次最多只能重建K个城市。
现在从大地震发生的那年开始,每年可以进行一个操作,也就是总共有M个操作。
1 x表示可以重建和x联通(直接或间接)的城市(包括x本身),每次最多只能重建K个城市
2 x y 表示修建了一条城市x到城市y的路。
3操作给出一个p,表示有p条路被摧毁了,然后给出p个x和y表示城市x和y之间的路被摧毁了。
要求全部操作完成后最多能重建多少个城市(每个城市最多只能被重建一次)
并且要求输出每次重建城市操作的全部计划的最小字典序。
样例:
1 5 6 2 2 1 2 2 1 3 1 1 1 2 3 1 1 2 1 2
表示第一年,修建了城市1和2之间的道路,第二年修建了城市1和3之间的道路。
所以第三年重建城市的时候,1和2和3都是联通的。但是因为要输出最小字典序,所以第三年不选择重建。即重建了0个城市
第四年1和2和3还是都联通的,选择重建城市1和城市3.即重建了2个城市
第五年,城市1和城市2之间的路被摧毁。
第六年,选择重建城市2,重建来1个城市。
所以总共重建了3个城市 输出 0 2 1
思路:
网络流。
在原来的基础上增加源点s和汇点t。
考虑城市,由于每个城市最多只能重建一次,所以以每个城市为点向汇点t连一条边,容量为1,费用为0.
考虑1操作。由于每次最多只能重建k个城市。所以由源点s向每个1操作连一条边,容量为K。
因为要最小字典序点方案。所以每次操作,先操作的费用大,后操作的费用小。可以设初始费用为M,然后后面每次-1.
然后对于每个1操作。再向当前可以重建的城市连一条边,容量为1,费用为0.
最后求最小费用最大流。方案就是源点向每个1操作连边的流量。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 1010 4 const int inf = 0x3f3f3f3f; 5 struct Edge 6 { 7 int from, to, cap, flow, cost; 8 Edge(int f, int t, int ca, int fl, int co) 9 { 10 from = f; to = t; cap = ca; flow = fl; cost = co; 11 } 12 }; 13 vector <Edge> edges; 14 vector <int> G[maxn]; 15 int n, m, s, t; 16 int d[maxn], p[maxn], a[maxn], inq[maxn]; 17 void AddEdge(int from, int to, int cap, int cost) 18 { 19 edges.push_back(Edge(from, to, cap, 0, cost)); 20 edges.push_back(Edge(to, from, 0, 0, -cost)); 21 m = edges.size(); 22 G[from].push_back(m-2); 23 G[to].push_back(m-1); 24 } 25 bool BellmanFord(int s, int t, int &flow, int &cost) 26 { 27 for(int i = 0; i <= n; i++) d[i] = inf; 28 memset(inq, 0, sizeof(inq)); 29 d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = inf; 30 31 queue<int> q; 32 q.push(s); 33 while(!q.empty()) 34 { 35 int u = q.front(); q.pop(); 36 inq[u] = 0; 37 for(int i = 0; i < G[u].size(); i++) 38 { 39 Edge &e = edges[G[u][i]]; 40 if(e.cap > e.flow && d[e.to] > d[u] + e.cost) 41 { 42 d[e.to] = d[u] + e.cost; 43 p[e.to] = G[u][i]; 44 a[e.to] = min(a[u], e.cap - e.flow); 45 if(!inq[e.to]) 46 { 47 q.push(e.to); inq[e.to] = 1; 48 } 49 } 50 } 51 } 52 if(d[t] == inf) return false; 53 flow += a[t]; 54 cost += d[t]*a[t]; 55 int u = t; 56 while(u!=s) 57 { 58 edges[p[u]].flow += a[t]; 59 edges[p[u]^1].flow -= a[t]; 60 u = edges[p[u]].from; 61 } 62 return true; 63 } 64 int flow = 0; 65 int Mincost() 66 { 67 int cost = 0; 68 while(BellmanFord(s, t, flow, cost)); 69 return cost; 70 } 71 int T, N, M, K; 72 int mp[220][220]; 73 vector <int> connect; 74 int vis[maxn]; 75 void dfs(int s) 76 { 77 for(int i = 1; i <= N; i++) 78 { 79 if(mp[s][i] == 1 && !vis[i]) 80 { 81 connect.push_back(i); 82 vis[i] = 1; 83 dfs(i); 84 } 85 } 86 return; 87 } 88 int main() 89 { 90 scanf("%d", &T); 91 while(T--) 92 { 93 scanf("%d%d%d", &N, &M, &K); 94 edges.clear(); 95 for(int i = 0; i <= N+M+1; i++) G[i].clear(); 96 memset(mp, 0, sizeof(mp)); 97 s = 0; t = N+M+1; n = N+M+1; 98 for(int i = 1; i <= N; i++) 99 { 100 mp[i][i] = 1; AddEdge(M+i, t, 1, 0); 101 } 102 int initcost = M, op, a, b, cnt = 0; 103 for(int i = 1; i <= M; i++) 104 { 105 scanf("%d", &op); 106 if(op == 1) 107 { 108 cnt++; 109 AddEdge(s, cnt, K, initcost); 110 initcost--; 111 scanf("%d", &a); 112 connect.clear(); 113 memset(vis, 0, sizeof(vis)); 114 dfs(a); 115 for(int j = 0; j < connect.size(); j++) 116 { 117 AddEdge(cnt, M+connect[j], 1, 0); 118 } 119 } 120 else if(op == 2) 121 { 122 scanf("%d%d", &a, &b); 123 mp[a][b] = mp[b][a] = 1; 124 } 125 else if(op == 3) 126 { 127 int p; scanf("%d", &p); 128 while(p--) 129 { 130 scanf("%d%d", &a, &b); 131 mp[a][b] = mp[b][a] = 0; 132 } 133 } 134 } 135 flow = 0; 136 int cost = Mincost(); 137 printf("%d\n", flow); 138 bool flag = true; 139 for(int i = 0; i < m; i += 2) 140 { 141 if(edges[i].from == s) 142 { 143 if(flag) printf("%d", edges[i].flow), flag = false; 144 else printf(" %d", edges[i].flow); 145 } 146 } 147 printf("\n"); 148 } 149 }
标签:
原文地址:http://www.cnblogs.com/titicia/p/4704427.html