題目鏈接:POJ 1087 A Plug for UNIX
A Plug for UNIX Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13809 Accepted: 4623
Description
You are in charge of setting up the press room for the inaugural meeting of the United Nations Internet eXecutive (UNIX), which has an international mandate to make the free flow of information and ideas on the Internet as cumbersome and bureaucratic as possible.Input
The input will consist of one case. The first line contains a single positive integer n (1 <= n <= 100) indicating the number of receptacles in the room. The next n lines list the receptacle types found in the room. Each receptacle type consists of a string of at most 24 alphanumeric characters. The next line contains a single positive integer m (1 <= m <= 100) indicating the number of devices you would like to plug in. Each of the next m lines lists the name of a device followed by the type of plug it uses (which is identical to the type of receptacle it requires). A device name is a string of at most 24 alphanumericOutput
A line containing a single non-negative integer indicating the smallest number of devices that cannot be plugged in.Sample Input
4 A B C D 5 laptop B phone C pager B clock B comb X 3 B X X A X D
Sample Output
1
Source
East Central North America 1999發現基本構圖好了,網絡流的題目就很好解了。
(1)以0為源點,1為匯點,其他的插座還有設備都作為中間點
(2)會議室提供n個插座,從源點到每個插座連一條邊,容量為1
(3)會議室有m個設備,從每個設備到匯點連一條邊,容量為1
(4)每個設備使用一個插座,從相應插座到設備連一條邊,容量為1
(5)有k中轉接器,從插頭到轉接器提供插座類型連一條邊,即前者可以轉化為後者,容量為無窮,因為可以串聯。
(6)求從源點到匯點最大流,及最多使用設備數目maxflow,最後結果為m-maxflow。
代碼;
Dinic:
#include#include #include #include #include #include using namespace std; #define maxn 1010 #define INF 0x3f3f3f3f struct Edge { int from, to, cap; }; vector EG; vector G[maxn]; int n, s, t, d[maxn], cur[maxn], mp[maxn][maxn]; char name[maxn][30]; int cnt; void addEdge(int from, int to, int cap) { EG.push_back((Edge){from, to, cap}); EG.push_back((Edge){to, from, 0}); int x = EG.size(); G[from].push_back(x-2); G[to].push_back(x-1); } bool bfs() { memset(d, -1, sizeof(d)); queue q; q.push(s); d[s] = 0; while(!q.empty()) { int x = q.front(); q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge& e = EG[G[x][i]]; if(d[e.to] == -1 && e.cap > 0) { d[e.to] = d[x]+1; q.push(e.to); } } } return (d[t]!=-1); } int dfs(int x, int a) { if(x == t || a == 0) return a; int flow = 0, f; for(int& i = cur[x]; i < G[x].size(); i++) { Edge& e = EG[G[x][i]]; if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap))) > 0) { e.cap -= f; EG[G[x][i]^1].cap += f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Dinic() { int ans = 0; while(bfs()) { memset(cur, 0, sizeof(cur)); ans += dfs(s, INF); } EG.clear(); for(int i = 0; i < n; ++i) G[i].clear(); return ans; } int Find(char* str) { int i; for(i = 2; i < cnt; ++i) if(strcmp(name[i], str) == 0) return i; strcpy(name[i], str); cnt++; return i; } int main() { //freopen("poj_1087.txt", "r", stdin); int m, k; char str1[30], str2[30]; while(~scanf("%d", &n)) { s = 0, t = 1; cnt = 2; //源點和匯點占兩個 for(int i = 0; i < n; i++) { scanf("%s", str1); strcpy(name[cnt], str1); //插座不會從父,直接插入 cnt++; addEdge(0, i+2, 1); //建邊,源點向每個插座連一條1的邊 } scanf("%d", &m); for(int i = 0; i < m; i++) { scanf("%s%s", str1, str2); strcpy(name[cnt], str1); //設備也不會重復。直接插入 cnt++; int u = Find(str2); //扎裡插座可能重復,要查找 addEdge(u, cnt-1, 1); //建邊,插座向設備連一條容量為1的邊 addEdge(cnt-1, 1, 1); //建邊,設備到匯點連一條邊,容量為1 } scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%s%s", str1, str2); int u = Find(str1); int v = Find(str2); addEdge(v, u, INF); //建邊,後者到前者容量為無窮 } n = cnt; int ans = Dinic(); printf("%d\n", m-ans); } return 0; }
#include#include #include #include #include #include using namespace std; #define maxn 1010 #define INF 0x3f3f3f3f struct Edge { int from, to, cap, flow; }; char name[maxn][30]; vector EG; vector G[maxn]; int n, s, t, d[maxn], cur[maxn], p[maxn], num[maxn], mp[maxn][maxn]; bool vis[maxn]; int cnt; void addEdge(int from, int to, int cap) { EG.push_back((Edge){from, to, cap, 0}); EG.push_back((Edge){to, from, 0, 0}); int x = EG.size(); G[from].push_back(x-2); G[to].push_back(x-1); } void bfs() { memset(vis, false, sizeof(vis)); queue q; vis[t] = true; d[t] = 0; q.push(t); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = 0; i < G[x].size(); i++) { Edge& e = EG[G[x][i]^1]; if(!vis[e.from] && e.cap > e.flow) { vis[e.from] = true; d[e.from] = d[x]+1; q.push(e.from); } } } } int augment() { int x = t, a = INF; while(x != s) { Edge& e = EG[p[x]]; a = min(a, e.cap-e.flow); x = EG[p[x]].from; } x = t; while(x != s) { EG[p[x]].flow += a; EG[p[x]^1].flow -= a; x = EG[p[x]].from; } return a; } int ISAP() { int ans =0; bfs(); memset(num, 0, sizeof(num)); for(int i = 0; i < n; i++) num[d[i]]++; int x = s; memset(cur, 0, sizeof(cur)); while(d[s] < n) { if(x == t) { ans += augment(); x = s; } bool flag = false; for(int i = cur[x]; i < G[x].size(); i++) { Edge& e = EG[G[x][i]]; if(e.cap > e.flow && d[x] == d[e.to]+1) { flag = true; p[e.to] = G[x][i]; cur[x] = i; x = e.to; break; } } if(!flag) { int m = n-1; for(int i = 0; i < G[x].size(); i++) { Edge& e = EG[G[x][i]]; if(e.cap > e.flow) m = min(m, d[e.to]); } if(--num[d[x]] == 0) break; num[d[x] = m+1]++; cur[x] = 0; if(x != s) x = EG[p[x]].from; } } EG.clear(); for(int i = 0; i < n; ++i) G[i].clear(); return ans; } int Find(char* str) { int i; for(i = 2; i < cnt; ++i) if(strcmp(name[i], str) == 0) return i; strcpy(name[i], str); cnt++; return i; } int main() { //freopen("poj_1087.txt", "r", stdin); int m, k; char str1[30], str2[30]; while(~scanf("%d", &n)) { s = 0, t = 1; cnt = 2; for(int i = 0; i < n; i++) { scanf("%s", str1); strcpy(name[cnt], str1); cnt++; addEdge(0, i+2, 1); } scanf("%d", &m); for(int i = 0; i < m; i++) { scanf("%s%s", str1, str2); strcpy(name[cnt], str1); cnt++; int u = Find(str2); addEdge(u, cnt-1, 1); addEdge(cnt-1, 1, 1); } scanf("%d", &k); for(int i = 0; i < k; i++) { scanf("%s%s", str1, str2); int u = Find(str1); int v = Find(str2); addEdge(v, u, INF); } n = cnt; int ans = ISAP(); printf("%d\n", m-ans); } return 0; }