UVa 753 - A Plug for UNIX(最大流)
Posted Ctfes
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa 753 - A Plug for UNIX(最大流)相关的知识,希望对你有一定的参考价值。
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=694
题意:
有n个插座,m个设备和k(n,m,k≤100)种转换器,每种转换器都有无限多。已知每个插座的类型,每个设备的插头类型,
以及每种转换器的插座类型和插头类型。插头和插座类型都用不超过24个字母表示,插头只能插到类型名称相同的插座中。
例如,有4个插座,类型分别为A, B, C, D;有5个设备,插头类型分别为B, C, B, B, X;
还有3种转换器,分别是B->X,X->A和X->D。这里用B->X表示插座类型为B,插头类型为X,
因此一个插头类型为B的设备插上这种转换器之后就“变成”了一个插头类型为X的设备。
转换器可以级联使用,例如插头类型为A的设备依次接上A->B,B->C,C->D这3个转换器之后会“变成”插头类型为D的设备。
要求插的设备尽量多。问最少剩几个不匹配的设备。
分析:
首先要注意的是:k个转换器中涉及的插头类型不一定是接线板或者设备中出现过的插头类型。
在最坏情况下,100个设备,100个插座,100个转换器最多会出现400种插头。
当然,400种插头的情况肯定是无解的,但是如果编码不当,这样的情况可能会让程序出现下标越界等运行错误。
转换器有无限多,所以可以独立计算出每个设备i是否可以接上0个或多个转换器之后插到第j个插座上,
方法是建立有向图G,结点表示插头类型,边表示转换器,然后使用Floyd算法,
计算出任意一种插头类型a是否能转化为另一种插头类型b。
接下来构造网络:设设备i对应的插头类型编号为device[i],插座i对应的插头类型编号为recep[i],
则源点s到所有device[i]连一条弧,容量为1,然后所有recep[i]到汇点t连一条弧,容量为1,
对于所有设备i和插座j,如果device[i]可以转化为recep[j],则从device[i]连一条弧到recep[j],容量为1,
最后求s-t最大流,答案就是m减去最大流量。
代码:
1 //Dinic版 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <map> 6 #include <vector> 7 #include <queue> 8 using namespace std; 9 10 /// 结点下标从0开始,注意maxn 11 struct Dinic { 12 static const int maxn = 1e3 + 5; 13 static const int INF = 0x3f3f3f3f; 14 struct Edge { 15 int from, to, cap, flow; 16 }; 17 18 int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号 19 vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧 20 vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 21 bool vis[maxn]; // BFS使用 22 int d[maxn]; // 从起点到i的距离 23 int cur[maxn]; // 当前弧下标 24 25 void init(int n) { 26 this->n = n; 27 edges.clear(); 28 for(int i = 0; i < n; i++) G[i].clear(); 29 } 30 void AddEdge(int from, int to, int cap) { 31 edges.push_back((Edge){from, to, cap, 0}); 32 edges.push_back((Edge){to, from, 0, 0}); 33 m = edges.size(); 34 G[from].push_back(m-2); 35 G[to].push_back(m-1); 36 } 37 bool BFS() { 38 memset(vis, 0, sizeof(vis)); 39 queue<int> Q; 40 Q.push(s); 41 vis[s] = 1; 42 d[s] = 0; 43 while(!Q.empty()) { 44 int x = Q.front(); Q.pop(); 45 for(int i = 0; i < G[x].size(); i++) { 46 Edge& e = edges[G[x][i]]; 47 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧 48 vis[e.to] = 1; 49 d[e.to] = d[x] + 1; 50 Q.push(e.to); 51 } 52 } 53 } 54 return vis[t]; 55 } 56 int DFS(int x, int a) { 57 if(x == t || a == 0) return a; 58 int flow = 0, f; 59 for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧 60 Edge& e = edges[G[x][i]]; 61 if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) { 62 e.flow += f; 63 edges[G[x][i]^1].flow -= f; 64 flow += f; 65 a -= f; 66 if(a == 0) break; 67 } 68 } 69 return flow; 70 } 71 int Maxflow(int s, int t) { 72 this->s = s; this->t = t; 73 int flow = 0; 74 while(BFS()) { 75 memset(cur, 0, sizeof(cur)); 76 flow += DFS(s, INF); 77 } 78 return flow; 79 } 80 vector<int> Mincut() { // 在Maxflow之后调用 81 vector<int> ans; 82 for(int i = 0; i < edges.size(); i++) { 83 Edge& e = edges[i]; 84 if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i); 85 } 86 return ans; 87 } 88 }; 89 90 const int UP = 100 + 5; 91 int recep[UP], device[UP]; 92 bool can[UP*4][UP*4]; 93 map<string,int> ids; 94 Dinic dc; 95 96 int id(string s) { 97 if(ids.count(s)) return ids[s]; 98 int i = ids.size(); 99 return ids[s] = i; 100 } 101 102 void floyd() { 103 int n = ids.size(); 104 for(int i = 0; i < n; i++) can[i][i] = true; 105 for(int k = 0; k < n; k++) { 106 for(int i = 0; i < n; i++) { 107 for(int j = 0; j < n; j++) { 108 can[i][j] |= can[i][k] && can[k][j]; 109 } 110 } 111 } 112 } 113 114 int main() { 115 int T, n, m, k; 116 char s[24+5], s2[24+5]; 117 scanf("%d", &T); 118 while(T--) { 119 ids.clear(); 120 memset(can, false, sizeof(can)); 121 scanf("%d", &n); 122 for(int i = 0; i < n; i++) { 123 scanf("%s", s); 124 recep[i] = id(s); 125 } 126 scanf("%d", &m); 127 for(int i = 0; i < m; i++) { 128 scanf("%s%s", s2, s); 129 device[i] = id(s); 130 } 131 scanf("%d", &k); 132 for(int i = 0; i < k; i++) { 133 scanf("%s%s", s, s2); 134 can[id(s)][id(s2)] = true; 135 } 136 137 floyd(); 138 int V = ids.size(); 139 dc.init(V+2); 140 for(int i = 0; i < m; i++) dc.AddEdge(V, device[i], 1); 141 for(int i = 0; i < n; i++) dc.AddEdge(recep[i], V+1, 1); 142 for(int i = 0; i < m; i++) { 143 for(int t = 0; t < n; t++) { 144 if(!can[device[i]][recep[t]]) continue; 145 dc.AddEdge(device[i], recep[t], 1); 146 } 147 } 148 printf("%d ", m - dc.Maxflow(V, V+1)); 149 if(T) printf(" "); 150 } 151 return 0; 152 }
1 //ISAP版 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <map> 6 #include <vector> 7 #include <queue> 8 using namespace std; 9 10 /// 结点下标从0开始,注意maxn 11 struct ISAP { 12 static const int maxn = 1e3 + 5; 13 static const int INF = 0x3f3f3f3f; 14 struct Edge { 15 int from, to, cap, flow; 16 }; 17 18 int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号 19 vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧 20 vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 21 bool vis[maxn]; // BFS使用 22 int d[maxn]; // 从起点到i的距离 23 int cur[maxn]; // 当前弧下标 24 int p[maxn]; // 可增广路上的上一条弧 25 int num[maxn]; // 距离标号计数 26 27 void init(int n) { 28 this->n = n; 29 edges.clear(); 30 for(int i = 0; i < n; i++) G[i].clear(); 31 } 32 void AddEdge(int from, int to, int cap) { 33 edges.push_back((Edge){from, to, cap, 0}); 34 edges.push_back((Edge){to, from, 0, 0}); 35 m = edges.size(); 36 G[from].push_back(m-2); 37 G[to].push_back(m-1); 38 } 39 bool BFS() { 40 memset(vis, 0, sizeof(vis)); 41 queue<int> Q; 42 Q.push(t); 43 vis[t] = 1; 44 d[t] = 0; 45 while(!Q.empty()) { 46 int x = Q.front(); Q.pop(); 47 for(int i = 0; i < G[x].size(); i++) { 48 Edge& e = edges[G[x][i]^1]; 49 if(!vis[e.from] && e.cap > e.flow) { 50 vis[e.from] = 1; 51 d[e.from] = d[x] + 1; 52 Q.push(e.from); 53 } 54 } 55 } 56 return vis[s]; 57 } 58 int Augment() { 59 int x = t, a = INF; 60 while(x != s) { 61 Edge& e = edges[p[x]]; 62 a = min(a, e.cap-e.flow); 63 x = edges[p[x]].from; 64 } 65 x = t; 66 while(x != s) { 67 edges[p[x]].flow += a; 68 edges[p[x]^1].flow -= a; 69 x = edges[p[x]].from; 70 } 71 return a; 72 } 73 int Maxflow(int s, int t) { 74 this->s = s; this->t = t; 75 int flow = 0; 76 BFS(); 77 memset(num, 0, sizeof(num)); 78 for(int i = 0; i < n; i++) num[d[i]]++; 79 int x = s; 80 memset(cur, 0, sizeof(cur)); 81 while(d[s] < n) { 82 if(x == t) { 83 flow += Augment(); 84 x = s; 85 } 86 int ok = 0; 87 for(int i = cur[x]; i < G[x].size(); i++) { 88 Edge& e = edges[G[x][i]]; 89 if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance 90 ok = 1; 91 p[e.to] = G[x][i]; 92 cur[x] = i; // 注意 93 x = e.to; 94 break; 95 } 96 } 97 if(!ok) { // Retreat 98 int m = n-1; // 初值注意 99 for(int i = 0; i < G[x].size(); i++) { 100 Edge& e = edges[G[x][i]]; 101 if(e.cap > e.flow) m = min(m, d[e.to]); 102 } 103 if(--num[d[x]] == 0) break; // gap优化 104 num[d[x] = m+1]++; 105 cur[x] = 0; // 注意 106 if(x != s) x = edges[p[x]].from; 107 } 108 } 109 return flow; 110 } 111 vector<int> Mincut() { // 在Maxflow之后调用 112 BFS(); 113 vector<int> ans; 114 for(int i = 0; i < edges.size(); i++) { 115 Edge& e = edges[i]; 116 if(!vis[e.from] && vis[e.to] && e.cap > 0) ans.push_back(i); 117 } 118 return ans; 119 } 120 }; 121 122 const int UP = 100 + 5; 123 int recep[UP], device[UP]; 124 bool can[UP*4][UP*4]; 125 map<string,int> ids; 126 ISAP is; 127 128 int id(string s) { 129 if(ids.count(s)) return ids[s]; 130 int i = ids.size(); 131 return ids[s] = i; 132 } 133 134 void floyd() { 135 int n = ids.size(); 136 for(int i = 0; i < n; i++) can[i][i] = true; 137 for(int k = 0; k < n; k++) { 138 for(int i = 0; i < n; i++) { 139 for(int j = 0; j < n; j++) { 140 can[i][j] |= can[i][k] && can[k][j]; 141 } 142 } 143 } 144 } 145 146 int main() { 147 int T, n, m, k; 148 char s[24+5], s2[24+5]; 149 scanf("%d", &T); 150 while(T--) { 151 ids.clear(); 152 memset(can, false, sizeof(can)); 153 scanf("%d", &n); 154 for(int i = 0; i < n; i++) { 155 scanf("%s", s); 156 recep[i] = id(s); 157 } 158 scanf("%d", &m); 159 for(int i = 0; i < m; i++) { 160 scanf("%s%s", s2, s); 161 device[i] = id(s); 162 } 163 scanf("%d", &k); 164 for(int i = 0; i < k; i++) { 165 scanf("%s%s", s, s2); 166 can[id(s)][id(s2)] = true; 167 } 168 169 floyd(); 170 int V = ids.size(); 171 is.init(V+2); 172 for(int i = 0; i < m; i++) is.AddEdge(V, device[i], 1); 173 for(int i = 0; i < n; i++) is.AddEdge(recep[i], V+1, 1); 174 for(int i = 0; i < m; i++) { 175 for(int t = 0; t < n; t++) { 176 if(!can[device[i]][recep[t]]) continue; 177 is.AddEdge(device[i], recep[t], 1); 178 } 179 } 180 printf("%d ", m - is.Maxflow(V, V+1)); 181 if(T) printf(" "); 182 } 183 return 0; 184 }
以上是关于UVa 753 - A Plug for UNIX(最大流)的主要内容,如果未能解决你的问题,请参考以下文章
UVa 753 - A Plug for UNIX(最大流)
题解 UVA753 UNIX插头 A Plug for UNIX