就向之前那篇博客写得一样,这里就是需要拆点的.把每头牛拆成:
饮料->牛->牛->食物.
想像一下,这样的话,如果有流量经过这条路线,就一定可以让这段流量同时经过牛-食物-饮料三件套.就可以保证解的正确性了~~~
Memory: 1580K | Time: 47MS |
用dinic写的.如果用其它算法(EK,sap,isap,FF都以),只是建图这里保证搞清楚 就好了.当然我们只是保证解的正确性,那你要问,我搞成食物->牛->牛->饮料可以不?当然是可以的!
好了,就这样了.
对了如果还不清楚,看我2小时前写得那篇总结.里面有关于拆点的说明,还有这种问题要加的"炒鸡源点"和"炒鸡汇点"这两个特殊点.
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
#include <queue>
using namespace std;
const int MAX_V = 512;
const int INF = INT_MAX>>1;
int G[MAX_V][MAX_V];
int level[MAX_V];
int n, f, d, all;
bool bfs(int s, int t) {
memset(level, -1, sizeof(level));
queue<int> Q; int p;
level[s] = 0;
Q.push(s);
while (!Q.empty()) {
p = Q.front(); Q.pop();
for (int i = 0; i < all; ++i) {
if (G[p][i] > 0 && level[i] < 0) {
level[i] = level[p] + 1;
Q.push(i);
if (i == t) return true;
}
}
}
return false;
}
int dfs(int s, int t, int flow) {
if (s == t) return flow;
int res = 0, tmp;
for (int i = 0; i < all; ++i) {
if (G[s][i] > 0 && level[i] == level[s] + 1) {
tmp = dfs(i, t, min(flow, G[s][i]));
G[s][i] -= tmp;
G[i][s] += tmp;
res += tmp; flow -= tmp;
}
}
return res;
}
int dinic(int s, int t) {
int flow = 0;
while (bfs(s, t)) flow += dfs(s, t, INF);
return flow;
}
int main() {
while (~scanf(" %d %d %d", &n, &f, &d)) {
memset(G, 0, sizeof(G));
/* 0炒鸡源点,1~f食物,f+1~f+n牛B,f+n+1~f+2*n牛屌,(牛要拆点
* f+2*n+1~f+2*n+d饮料,f+2*n+d+1炒鸡汇点
*/
all = f+(n<<1)+d+2;
for (int i = 1; i <= f; ++i) G[0][i] = 1;
for (int i = f+(n<<1)+1; i < all; ++i) G[i][all-1] = 1;
int cf, cd, val; //cow's food, cow's drink, value of anyone of them
for (int i = 1; i <= n; ++i) {
scanf(" %d %d", &cf, &cd);
for (int j = 1; j <= cf; ++j) {
scanf(" %d", &val);
G[val][i+f] = 1;
}//食物和牛逼连起来
G[i+f][i+f+n] = 1; //牛逼和牛屌连以来
for (int j = 1; j <= cd; ++j) {
scanf(" %d", &val);
G[i+f+n][f+(n<<1)+val] = 1;
}//牛屌和饮料连起来
}
printf("%d\n", dinic(0, all-1));
}
return 0;
}
呃,至于邻接矩阵被吐槽,是因为我智力有限,觉得这玩意方便....链表之后补学一下..........