1. 程式人生 > >UVa 753 - A Plug for UNIX(最大流)

UVa 753 - A Plug for UNIX(最大流)

printf ron 所有 ont flow new 使用 string can

鏈接:

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\n", m - dc.Maxflow(V, V+1)); 149 if(T) printf("\n"); 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\n", m - is.Maxflow(V, V+1));
181         if(T) printf("\n");
182     }
183     return 0;
184 }

UVa 753 - A Plug for UNIX(最大流)