# POJ 1149 PIGS

34 篇文章 0 订阅

#include <string>
#include <cmath>
#include <queue>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
//调用方法：
#define MAXN 1110 //顶点个数
#define MAXM MAXN*MAXN //边的条数
#define INF 1000000000
struct Edge {
int a, b; //边a->b
int c, f; //容量c,流量f
Edge *next, *back; //下一条边next,反向边back
void setEdge(int a, int b, int c, Edge *next) {
this->a = a;
this->b = b;
this->c = c;
this->next = next;
this->back = NULL;
this->f = 0;
}
} *edge[MAXN], nextEdge[MAXM];
int dist[MAXN]; //距离标号
int edgeNum = 0; //己经使用的边的个数
int counts[MAXN]; //各标号个数,出现断屋即无增广路
void init(int n) {
for(int i = 0; i < n; ++i) {		///0~n-1		？？
edge[i] = NULL;
counts[i] = 0;
}
edgeNum = 0;
}
void init_label(int n, int s, int t) {//顶点个数n，源s, 汇t
queue<int> que;
que.push(t);
memset(dist, -1, sizeof(dist));
//for(int i = 0; i < MAXN; ++i) {
// dist[i] = -1;
//}
dist[t] = 0;
++counts[dist[t]];
while(!que.empty()) {
int now = que.front();
que.pop();
for(Edge *next = edge[now]; next != NULL; next = next->next) {
if(next->f != 0) continue;
int b = next->b;
if(dist[b] == -1) {
dist[b] = dist[now] + 1;
++counts[dist[b]];
que.push(b);
}
}
}
}
void addEdge(int x, int y, int c) {//增加一条x->y的弧，容量为c
nextEdge[edgeNum].setEdge(x, y, c, edge[x]);
nextEdge[edgeNum + 1].setEdge(y, x, 0, edge[y]);
edge[x] = &nextEdge[edgeNum];
edge[y] = &nextEdge[edgeNum + 1];
edge[x]->back = edge[y];
edge[y]->back = edge[x];
edgeNum += 2;
}
int maxFlow(int n, int s, int t) {
int ret = 0;
init_label(n, s, t);
Edge *path[MAXN]; //如果MAXN很大，可以开全局数组
Edge *current[MAXN]; //如果MAXN很大，可以开全局数组
memcpy(current, edge, sizeof(edge));
int path_n = 0; //路径长度
int i = s;
while(1) {
if(i == t) { //找到增广路
int minFlow = INF, minK; //最小流和瓶颈位置值
for(int k = 0; k < path_n; ++k) {
if(path[k]->c < minFlow) {
minFlow = path[k]->c;
minK = k;
}
}
ret += minFlow;
for(int k = 0; k < path_n; ++k) {
path[k]->c -= minFlow;
path[k]->back->c += minFlow;
path[k]->f += minFlow;
path[k]->back->f = -(path[k]->f);
}
path_n = minK;
i = path[path_n]->a;
}
if(dist[i] != 0 && counts[dist[i] - 1] == 0) break;
Edge *next;
for(next = current[i]; next != NULL; next = next->next) {
if(next->c == 0) continue;
int y = next->b;
if(dist[i] == dist[y] + 1) {
break;
}
}
if(next != NULL) { //next是一张允许弧
current[i] = next;
path[path_n++] = next;
i = next->b;
} else { //无允许弧，修改标号
int minLabel = n;
for(Edge * next = edge[i]; next != NULL; next = next->next) {
if(next->c == 0) continue;
int y = next->b;
if(dist[y] < minLabel) {
minLabel = dist[y];
current[i] = next; //最小标号就是最新的允许弧
}
}
--counts[dist[i]];
dist[i] = minLabel + 1;
++counts[dist[i]];
if(i != s) { //路径改变，顶点肯定不是允许弧
--path_n;
i = path[path_n]->a;
} else if(dist[i] > n){ //没有增广路
return ret;
}
}
}
return ret;
}

// 顾客在买完猪便将门锁上，而且顾客是按照顺序来的。
int pre[1002];
int main()
{
int tn, tm;
while(scanf("%d%d", &tm, &tn)!=EOF)
{
memset(pre, -1, sizeof(pre));
init(tm+tn+2);
for(int i=0; i<tm; i++)
{
int tt;
scanf("%d", &tt);
}
for(int i=0; i<tn; i++)
{
int ta; scanf("%d", &ta);
while(ta--)
{
int tk; scanf("%d", &tk);
if(pre[tk]==-1)
else
pre[tk] = i+tm;
}
int tb; scanf("%d", &tb);
}
printf("%d\n", maxFlow(tm+tn+2, tm+tn, tm+tn+1));		//0-th
}
}


• 0
点赞
• 0
收藏
觉得还不错? 一键收藏
• 打赏
• 0
评论
11-17
09-20
09-19
08-21 9142
08-07 6284
08-05 2748
10-28 2053
11-01 1341
10-28 1226
08-05 1189
08-20 1139
11-01 1003
10-30 1001
10-06 978
05-18 882
02-23 8230

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。