POJ_1149 PIGS (网络流)

  /*拿到这题确实不知道怎么建图,问师兄,师兄讲了半天我也没听懂,后来看了 
Edelweiss大牛的《网络流建模汇总》,第一个就是讲的这道题。

大体思路是建立一个很直观的模型,但是复杂度太高,然后根据所找到的规律删边,最后
可以得到简单的建图规律:

1、从源点S到访问第i个猪圈的第一个人建一条边,容量Ci 就是猪圈里猪的头数,后边如果
再有顾客访问第i个猪圈,则从一个访问者到后来访问的顾客建一条边,容量为 +∞ 表示他
们之间可以相互联通。

2、如果从源点到一名顾客有多条边,则把这些边的合成一条边,容量累加。

3、每一个顾客到汇点T建一条边,容量就是顾客要买的猪数。


PS:网络流难的不是Dinic,SAP什么的,难的是建图啊。。。T_T

My Code:
*/

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

const int N = 110;
const int M = 1024;
const int inf = 0x6fffffff;

struct pig {
int cos[N];
int num;
int n;
}p[M];

int T;
int c[N];
int g[N][N];
int layer[N];
bool vis[N];

bool Layer() {
deque<int> q;
int i, v;
memset(layer, -1, sizeof(layer));
q.push_back(0);
layer[0] = 1;

while( !q.empty() ) {
v = q.front();
q.pop_front();

for( i = 0; i <= T; i++ ) {
if(g[v][i] > 0 && layer[i] == -1) {
layer[i] = layer[v] + 1;
if(i == T) {q.clear(); return true;}
else q.push_back(i);
}
}
}
return false;
}

int Dinic() {
deque<int> q;
int i, v, ve, vs, min, min_s, sum = 0;

while(Layer()) {
memset(vis, false, sizeof(vis));
q.push_back(0);
vis[0] = true;

while(!q.empty()) {
v = q.back();
if(v == T) {
min = inf;
for(i = 1; i < q.size(); i++) {
vs = q[i-1], ve = q[i];
if(g[vs][ve] > 0 && min > g[vs][ve]) {
min = g[vs][ve];
min_s = vs;
}
}
sum += min;
for(i = 1; i < q.size(); i++) {
vs = q[i-1]; ve = q[i];
if(g[vs][ve] > 0) {
g[vs][ve] -= min;
g[ve][vs] += min;
}
}
while(!q.empty() && q.back() != min_s) {
vis[q.back()] = false;
q.pop_back();
}
} else {
for(i = 0; i <= T; i++) {
if(g[v][i] > 0 && !vis[i] && layer[i] == layer[v] + 1) {
vis[i] = true;
q.push_back(i);
break;
}
}
if(i > T) q.pop_back();
}
}
}
return sum;
}

int main() {
//freopen("data.in", "r", stdin);

int N, M, i, k, j, x;
scanf("%d%d", &M, &N);

for(i = 1; i <= M; i++) {
scanf("%d", &p[i].num);
}
for(i = 1; i <= N; i++) {
scanf("%d", &k);
for(j = 1; j <= k; j++) {
scanf("%d", &x);
p[x].cos[p[x].n++] = i;
}
scanf("%d", &c[i]);
}
T = N + 1;
for(i = 1; i <= M; i++) {
if(p[i].n != 0) {
g[0][p[i].cos[0]] += p[i].num;
for(j = 1; j < p[i].n; j++) {
g[p[i].cos[0]][p[i].cos[j]] = inf;
}
}
}
for(i = 1; i <= N; i++)
g[i][T] = c[i];

printf("%d\n", Dinic());
return 0;
}
原文地址:https://www.cnblogs.com/vongang/p/2251278.html