码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1711:ISAP

时间:2016-01-07 21:30:09      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:

把牛拆成两个点i1和i2。从喜欢的食物到i1、i1到i2、i2到喜欢的饮料分别连边,容量都为1。再从源点到所有食物、所有饮料到汇点连边,容量同样为1。神解。原理很明显。全过程自己打的。第二道最大流。

-----------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
#define clr(x,c) memset(x,c,sizeof(x))
const int inf=0x3f3f3f3f;
const int nmax=405;
int read(){
 int x=0,f=1;char c=getchar();
 while(!isdigit(c)){
  if(c==‘-‘) f=-1;
  c=getchar();
 }
 while(isdigit(c)){
  x=x*10+c-‘0‘;
  c=getchar();
 }
 return x*f;
}


struct edge{
 int to,cap;
 edge *next,*rev;
};
edge e[400000];
int d[nmax],cnt[nmax];
edge *p[nmax],*head[nmax],*cur[nmax],*pt;
void add(int u,int v,int d){
 pt->to=v;
 pt->cap=d;
 pt->next=head[u];
 head[u]=pt++;
}
void adde(int u,int v,int d){
 add(u,v,d);
 add(v,u,0);
 head[u]->rev=head[v];
 head[v]->rev=head[u];
}


int maxflow(int s,int t,int n){
 clr(cnt,0);cnt[0]=n;
 clr(d,0);
 int x=s,a=inf,flow=0;
 while(d[s]<n){
  edge *ee;
  for(ee=cur[x];ee;ee=ee->next){
   if(ee->cap>0&&d[ee->to]+1==d[x])
     break;
  }
  if(ee){
   p[ee->to]=cur[x]=ee;
   x=ee->to;
   a=min(ee->cap,a);
   if(x==t){
    while(x!=s){
     p[x]->cap-=a;
     p[x]->rev->cap+=a;
     x=p[x]->rev->to;
    }
    flow+=a;
    a=inf;
   }
  }else{
   if(--cnt[d[x]]==0) break;
   d[x]=n;//差了这一句!!!
   for(ee=head[x];ee;ee=ee->next){
    if(ee->cap>0&&d[ee->to]+1<d[x]){
     d[x]=d[ee->to]+1;
     cur[x]=ee;
    }
   }
   cnt[d[x]]++;
   if(x!=s) x=p[x]->rev->to;
  }
 }
 return flow;
}


int main(){
 int N=read(),F=read(),D=read();
 int s=0,t=F+N+N+D+1;
 pt=e;clr(head,0);
 rep(i,F) adde(s,i,1);
 rep(i,N)    adde(F+i,F+N+i,1);
 rep(i,D)    adde(F+N+N+i,t,1);
    rep(i,N){
     int tmp=read(),tmp1=read();
     rep(j,tmp)   adde(read(),F+i,1);
     rep(j,tmp1)   adde(F+N+i,F+N+N+read(),1);
    }
    /*rep(i,t){
     for(edge*ee=head[i];ee;ee=ee->next)
       printf("%d %d\n",ee->to,ee->cap);
    }*/
    printf("%d\n",maxflow(s,t,t+1));
    return 0;
}

-----------------------------------------------------------------------------------------

1711: [Usaco2007 Open]Dingin吃饭

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 678  Solved: 347
[Submit][Status][Discuss]

Description

农夫JOHN为牛们做了很好的食品,但是牛吃饭很挑食. 每一头牛只喜欢吃一些食品和饮料而别的一概不吃.虽然他不一定能把所有牛喂饱,他还是想让尽可能多的牛吃到他们喜欢的食品和饮料. 农夫JOHN做了F (1 <= F <= 100) 种食品并准备了D (1 <= D <= 100) 种饮料. 他的N (1 <= N <= 100)头牛都以决定了是否愿意吃某种食物和喝某种饮料. 农夫JOHN想给每一头牛一种食品和一种饮料,使得尽可能多的牛得到喜欢的食物和饮料. 每一件食物和饮料只能由一头牛来用. 例如如果食物2被一头牛吃掉了,没有别的牛能吃食物2.

Input

* 第一行: 三个数: N, F, 和 D

* 第2..N+1行: 每一行由两个数开始F_i 和 D_i, 分别是第i 头牛可以吃的食品数和可以喝的饮料数.下F_i个整数是第i头牛可以吃的食品号,再下面的D_i个整数是第i头牛可以喝的饮料号码.

Output

* 第一行: 一个整数,最多可以喂饱的牛数.

Sample Input

4 3 3
2 2 1 2 3 1
2 2 2 3 1 2
2 2 1 3 1 2
2 1 1 3 3

输入解释:

牛 1: 食品从 {1,2}, 饮料从 {1,2} 中选
牛 2: 食品从 {2,3}, 饮料从 {1,2} 中选
牛 3: 食品从 {1,3}, 饮料从 {1,2} 中选
牛 4: 食品从 {1,3}, 饮料从 {3} 中选

Sample Output

3
输出解释:

一个方案是:
Cow 1: 不吃
Cow 2: 食品 #2, 饮料 #2
Cow 3: 食品 #1, 饮料 #1
Cow 4: 食品 #3, 饮料 #3
用鸽笼定理可以推出没有更好的解 (一共只有3总食品和饮料).当然,别的数据会更难.

HINT

 

Source

[Submit][Status][Discuss]

bzoj1711:ISAP

标签:

原文地址:http://www.cnblogs.com/fighting-to-the-end/p/5111238.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!