P1231 教輔的組成
阿新 • • 發佈:2018-08-04
最大流 bre const write queue return cstring \n tac
傳送門:https://www.luogu.org/problemnew/show/P1231
這是一道很不錯的網絡流入門題,關鍵在於如何建圖。
首先,我們將練習冊和源點連一條邊權為1的邊,然後若書 i 和練習冊 j 可以配套,就將連一條從練習冊 j 到書 i 邊,當然邊權還是1。同理,答案和書也是如此,最後再將答案和匯點連一條邊權為1的邊。
但是這麽寫還是會有點問題,因為經過一本書的路徑可能與很多條,書就被使用了多次,顯然不符合題意。這時候我們可以將書 i 拆成書 i1 和 i2,i1 和練習冊連邊,i2 和答案連邊,這樣就保證沒一本書之用過一次了。
建好圖後跑最大流就行了。
1 #include<cstdio> 2#include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 #define enter printf("\n") 13#define space printf(" ") 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 1e4 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ‘ ‘; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) 26 { 27 ans = ans * 10 + ch - ‘0‘; ch = getchar(); 28 } 29 if(last == ‘-‘) ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) x = -x, putchar(‘-‘); 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + ‘0‘); 37 } 38 39 int t, n1, n2, n3; 40 41 struct Edge 42 { 43 int from, to, cap, flow; 44 }; 45 vector<Edge> edges; 46 vector<int> G[maxn << 2]; 47 void addEdge(int from, int to) 48 { 49 edges.push_back((Edge){from, to, 1, 0}); 50 edges.push_back((Edge){to, from, 0, 0}); 51 int sz = edges.size(); 52 G[from].push_back(sz - 2); 53 G[to].push_back(sz - 1); 54 } 55 56 int dis[maxn << 2]; 57 bool vis[maxn << 2]; 58 bool bfs() 59 { 60 Mem(vis); 61 queue<int> q; 62 q.push(0); vis[0] = 1; 63 dis[0] = 0; 64 while(!q.empty()) 65 { 66 int now = q.front(); q.pop(); 67 for(int i = 0; i < (int)G[now].size(); ++i) 68 { 69 Edge& e = edges[G[now][i]]; 70 if(!vis[e.to] && e.cap > e.flow) 71 { 72 vis[e.to] = 1; 73 dis[e.to] = dis[now] + 1; 74 q.push(e.to); 75 } 76 } 77 } 78 return vis[t]; 79 } 80 int cur[maxn << 2]; 81 int dfs(int now, int a) 82 { 83 if(now == t || !a) return a; 84 int flow = 0, f; 85 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 86 { 87 Edge& e = edges[G[now][i]]; 88 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) 89 { 90 e.flow += f; 91 edges[G[now][i] ^ 1].flow -= f; 92 flow += f; a -= f; 93 if(!a) break; 94 } 95 } 96 return flow; 97 } 98 99 int maxflow() 100 { 101 int flow = 0; 102 while(bfs()) 103 { 104 Mem(cur); 105 flow += dfs(0, INF); 106 } 107 return flow; 108 } 109 110 //bool vis2[maxn]; 111 112 int main() 113 { 114 n1 = read(); n2 = read(); n3 = read(); 115 t = (n1 << 1)+ n2 + n3 + 1; //為了防止編號重復 116 /*按註釋掉的寫法會WA掉,因為如果一本書多次輸入,那麽這個書 117 就多次拆點,這一本書就可以使用多次了 */ 118 /* int m = read(); 119 while(m--) 120 { 121 int x = read(), y = read(); 122 addEdge(0, y + (n1 << 1)); 123 addEdge(y + (n1 << 1), x); 124 addEdge(x, x + n1); 125 vis2[x] = 1; 126 } 127 m = read(); 128 while(m--) 129 { 130 int x = read(), y = read(); 131 if(!vis2[x]) addEdge(x, x + n1), vis2[x] = 1; 132 addEdge(x + n1, y + (n1 << 1) + n2); 133 addEdge(y + (n1 << 1) + n2, t); 134 }*/ 135 int m = read(); 136 while(m--) 137 { 138 int x = read(), y = read(); 139 addEdge(y + (n1 << 1), x); 140 } 141 m = read(); 142 while(m--) 143 { 144 int x = read(), y = read(); 145 addEdge(x + n1, y + (n1 << 1) + n2); 146 } 147 for(int i = 1; i <= n1; ++i) addEdge(i, i + n1); 148 for(int i = 1; i <= n2; ++i) addEdge(0, i + (n1 << 1)); 149 for(int i = 1; i <= n3; ++i) addEdge(i + (n1 << 1) + n2, t); 150 write(maxflow()); enter; 151 }
P1231 教輔的組成