网络流( ISAP + 拆点 )——Dining ( POJ 3281 )
2016-07-27 14:02
411 查看
题目链接:
http://poj.org/problem?id=3281
分析:
一头牛只吃指定的几种食物或饮料,但是每一种食物和饮料都只有一个,给出N头牛及其要求,F种食物和D种饮料,问最多可以满足多少头牛的需要(饮料和食物都满足需求)。
题解:
1.建图:需要将每头牛拆成牛1和牛2,然后建立一个源点S,从S出发作边连接每一个食物,容量为1。然后从食物出发向和其对应的牛做边,容量为1。再连接牛1和牛2,容量为1。从牛2出发向与其对应的饮料作边,容量为1。再连接饮料与汇点,容量为1。
2.BFS:
3.ISAP:
AC代码:
http://poj.org/problem?id=3281
分析:
一头牛只吃指定的几种食物或饮料,但是每一种食物和饮料都只有一个,给出N头牛及其要求,F种食物和D种饮料,问最多可以满足多少头牛的需要(饮料和食物都满足需求)。
题解:
1.建图:需要将每头牛拆成牛1和牛2,然后建立一个源点S,从S出发作边连接每一个食物,容量为1。然后从食物出发向和其对应的牛做边,容量为1。再连接牛1和牛2,容量为1。从牛2出发向与其对应的饮料作边,容量为1。再连接饮料与汇点,容量为1。
//邻接链表存储边 int head[Maxn]; struct node { int v, cap; //v为该点连的当前边另一端的点,cap为当前边边的容量 int next;//该点连接的下一条边 }edge[80000]; void add(int u, int v, int cap)//添加边 { edge[cont].v = v; edge[cont].cap = cap; edge[cont].next = head[u]; head[u] = cont++; edge[cont].v=u; //反向建边,容量为0 edge[cont].cap=0; edge[cont].next=head[v]; head[v] = cont++; }
2.BFS:
int dis[Maxn]; int num[Maxn]; void BFS(int source,int sink) { queue<int>q; while(!q.empty()) q.pop(); memset(num,0,sizeof(num)); memset(dis,-1,sizeof(dis)); q.push(sink); dis[sink]=0; num[0]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i = head[u]; i! = -1; i = edge[i].next) { int v = edge[i].v; if(dis[v] == -1) { dis[v] = dis[u] + 1; num[dis[v]]++; q.push(v); } } } }
3.ISAP:
int cur[Maxn]; int pre[Maxn]; int ISAP(int source,int sink,int n) { memcpy(cur,head,sizeof(cur)); int flow=0, u = pre[source] = source; BFS(source, sink); while( dis[source] < n ) { if(u == sink) { int df = INF, pos; for(int i =source;i != sink;i = edge[cur[i]].v) { if(df > edge[cur[i]].cap) { df = edge[cur[i]].cap; pos = i; } } for(int i = source;i != sink;i = edge[cur[i]].v) { edge[cur[i]].cap -= df; edge[cur[i]^1].cap += df; } flow += df; u = pos; } int st; for(st = cur[u];st != -1;st = edge[st].next) { if(dis[edge[st].v] + 1 == dis[u] && edge[st].cap) { break; } } if(st != -1) { cur[u] = st; pre[edge[st].v] = u; u = edge[st].v; } else { if( (--num[dis[u]])==0 ) break; int mind = n; for(int id = head[u];id != -1;id = edge[id].next) { if(mind > dis[edge[id].v] && edge[id].cap != 0) { cur[u] = id; mind = dis[edge[id].v]; } } dis[u] = mind+1; num[dis[u]]++; if(u!=source) u = pre[u]; } } return flow; }
AC代码:
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define Maxn 2000 #define INF 99999999 struct node { int v, cap; int next; }edge[80000]; int N,F,D; int cont; int head[Maxn]; int dis[Maxn]; int num[Maxn]; int cur[Maxn]; int pre[Maxn]; void add(int u, int v, int cap) { edge[cont].v = v; edge[cont].cap = cap; edge[cont].next = head[u]; head[u] = cont++; edge[cont].v=u; edge[cont].cap=0; edge[cont].next=head[v]; head[v] = cont++; } void BFS(int source,int sink) { queue<int>q; while(q.empty()==false) q.pop(); memset(num,0,sizeof(num)); memset(dis,-1,sizeof(dis)); q.push(sink); dis[sink]=0; num[0]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v = edge[i].v; if(dis[v] == -1) { dis[v] = dis[u] + 1; num[dis[v]]++; q.push(v); } } } } int ISAP(int source,int sink,int n) { memcpy(cur,head,sizeof(cur)); int flow=0, u = pre[source] = source; BFS( source,sink); while( dis[source] < n ) { if(u == sink) { int df = INF, pos; for(int i =source;i != sink;i = edge[cur[i]].v) { if(df > edge[cur[i]].cap) { df = edge[cur[i]].cap; pos = i; } } for(int i = source;i != sink;i = edge[cur[i]].v) { edge[cur[i]].cap -= df; edge[cur[i]^1].cap += df; } flow += df; u = pos; } int st; for(st = cur[u];st != -1;st = edge[st].next) { if(dis[edge[st].v] + 1 == dis[u] && edge[st].cap) { break; } } if(st != -1) { cur[u] = st; pre[edge[st].v] = u; u = edge[st].v; } else { if( (--num[dis[u]])==0 ) break; int mind = n; for(int id = head[u];id != -1;id = edge[id].next) { if(mind > dis[edge[id].v] && edge[id].cap != 0) { cur[u] = id; mind = dis[edge[id].v]; } } dis[u] = mind+1; num[dis[u]]++; if(u!=source) u = pre[u]; } } return flow; } void init() { memset(head,-1,sizeof(head)); cont=0; } int main() { int a,b,c; while(~scanf("%d%d%d", &N, &F, &D)) { init(); int S = 0; int T = 2*N+F+D+1; for(int i = 1; i<=F; i++) //建立源点到所有食物 { add(S, i, 1); } for(int i = 1; i<=N; i++) { scanf("%d%d",&a,&b); for(int j = 1;j<=a;j++) { scanf("%d",&c); add(c,F+i,1);//食物到牛 } for(int j = 1;j<=b;j++) { scanf("%d",&c); add(F+i+N,2*N+F+c,1);//牛' 到饮料 } add(F+i,F+i+N,1);//牛 到 牛’ } for(int i = 1;i<=D;i++) { add(2*N+F+i, T,1);//食物 到汇点 } int ans = ISAP(S, T, T+1 ); printf("%d\n",ans); } return 0; }
相关文章推荐
- 简单的四则运算
- 数的奇偶性
- ACMer博客瀑布流分析
- ACM程序设计大赛题目分类
- 2015年acm国内排名
- 计算字符串最后一个单词长度
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- 矩阵的乘法操作
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂
- HDOJ 1002 A + B Problem II (Big Numbers Addition)
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1002