首页 > 代码库 > POJ 3281 Dining(最大流建图 && ISAP && 拆点)
POJ 3281 Dining(最大流建图 && ISAP && 拆点)
题目链接:http://poj.org/problem?id=3281
努力练建图ing!!!
题意:有 N 头牛,有 F 种食物和 D 种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。
第2行-第N+1行。是牛i 喜欢A种食物,B种饮料,及食物种类列表和饮料种类列表。
问最多能使几头牛同时享用到自己喜欢的食物和饮料。->最大流。
本题难点是建图:
思路:一般都是左边一个集合表示源点与供应相连,右边一个集合表示需求与汇点相连。
但是本题,牛作为需求仍然是一个群体,但是供应却有食物和饮料两个集合,所以把一头拆成两头牛:
牛本体(牛/入点)、牛的分身(牛‘/出点)
建图方式:源点->食物 、食物->牛 、 牛->牛’ 、 牛’ ->饮料 、饮料->汇点.
ID 3281 | Accepted | 240K | 0MS | C++ |
加上 !=EOF是16ms ,真奇怪。。。不加竟然是0ms
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int N = 210; const int maxn = 2000; const int maxm = 80000; #define MIN INT_MIN #define MAX INT_MAX #define LL long long #define max(a,b) (a>b)?(a):(b) #define min(a,b) (a>b)?(b):(a) using namespace std; int head[maxn], sum, bnum; int dis[maxn]; int num[maxn]; int cur[maxn]; int pre[maxn]; struct node { int v, cap; int next; }edge[maxm]; void add(int u, int v, int cap) { edge[bnum].v=v; edge[bnum].cap=cap; edge[bnum].next=head[u]; head[u]=bnum++; edge[bnum].v=u; edge[bnum].cap=0; edge[bnum].next=head[v]; head[v]=bnum++; } 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 = MAX, 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 initt() { memset(head,-1,sizeof(head)); bnum=0; } int main() { int n,F,D; int a,b,c; while(scanf("%d%d%d",&n,&F,&D)!=EOF) { initt(); int source = 0,sink = 2*n+F+D+1; for(int i = 1;i<=F;i++) //建立源点到所有食物 { add(source,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,sink,1);//食物 到汇点 } int ans = ISAP(source,sink,sink+1); printf("%d\n",ans); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。