POJ 3281 Dining & HDU 4292 Food【最大流】

这两题基本一样

POJ 3281

链接

题意:

有N个牛,F个食物,D个饮料,每个牛只吃其中若干种食物和饮料,规定每个牛要么不吃,要么食物和饮料各吃一种,各种食物和饮料都只有一个。求最多多少牛能得到满足(吃食物+饮料)

输入格式:

给牛的数量N,食物数量F,饮料数量D

接下来的N行(1到N号牛),然后TF,TD,接下来TF个食物编号,TD个饮料编号,表示 i 号牛只吃这TF个食物,TD个饮料

建图:

首先知道要把牛分点,分为牛1,牛2,如果不分则建图为

食物->牛->饮料,若牛选了食物A,饮料B,则若食物C,饮料D也跟牛有边,则被算法认为是增广路,但这并不满足每牛只能吃一种饮料和食物。

所以要变为:

源点S->食物->牛1->牛2->饮料->汇点T,所有容量为1。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define eps 10^(-6)
#define Q_CIN ios::sync_with_stdio(false)
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define CLR( a , x ) memset ( a , x , sizeof (a) )
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define NMAX 10002
#define min(a,b) ((a)>(b)?(b):(a))
#define max(a,b) ((a)<(b)?(b):(a))
const int inf=0x3f3f3f3f;
const int maxn=2*100+105+105;
int ss,tt;
int cap[maxn][maxn],dis[maxn];

int bfs(int s,int t)
{
    queue<int>q;
    q.push(s);
    CLR(dis,-1);
    dis[s]=0;
    while(!q.empty()){
        int tmp=q.front();q.pop();
        FOR(i,s,t){
            if(dis[i]<0&&cap[tmp][i]){
                dis[i]=dis[tmp]+1;
                q.push(i);
            }
        }
    }
    if(dis[t]>0) return 1;
    return 0;
}

int dfs(int s,int t,int low){
    int flow;
    if(s==t)   return low;
    FOR(i,ss,tt){   //ss->tt
        if(cap[s][i]
           &&(dis[i]==dis[s]+1)
           &&(flow=dfs(i,t,min(cap[s][i],low)))){
            cap[s][i]-=flow;
            cap[i][s]+=flow;
            return flow;
        }
    }
    return 0;
}


int main()
{
//    freopen("1.in","r",stdin);
    int n,f,d;
    int tf,td,tx;
    while(cin>>n>>f>>d){
        ss=0,tt=2*n+f+d+1;
        CLR(cap,0);
        FOR(i,1,n){
            cin>>tf>>td;
            while(tf--){
                cin>>tx;
                tx+=2*n;
                cap[ss][tx]=1;    //src to food
                cap[tx][i]=1;       //food to cow
            }
            while(td--){
                cin>>tx;
                tx+=2*n+f;
                cap[tx][tt]=1;      //drink to end
                cap[i+n][tx]=1;   //cow to drink
            }
            cap[i][i+n]=1;      //cow1 to cow2
        }
        int ans=0;
        while(bfs(ss,tt)){
            ans+=dfs(ss,tt,inf);
        }
        cout<<ans<<endl;
    }
}


HDU 4292 Food
此题邻接矩阵Dinic过不了,邻接表600MS,在DFS中加个//dis[u]=-1;就100MS!
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define eps 10^(-6)
#define Q_CIN ios::sync_with_stdio(false);
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define CLR( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define debug(x) cout<<#x<<":"<<(x)<<endl;
#define sc(x) scanf("%d",&x);
#define lson i<<1,l,m
#define rson i<<1|1,m+1,r
const int maxn=805;
const int maxm=200005;
const int inf=0x3f3f3f3f;
int dis[maxn];
int ss,tt;
int cnt;
int head[maxn],q[maxn];
struct Edge
{
    int v,w,next;
}edge[maxm*2];
void addEdge(int u,int v,int w)
{
    edge[cnt].v=v,edge[cnt].w=w,edge[cnt].next=head[u];head[u]=cnt++;
    edge[cnt].v=u,edge[cnt].w=0,edge[cnt].next=head[v];head[v]=cnt++;
}
void init()
{
    CLR(head,-1);
    cnt=0;
}
int bfs()
{
    queue<int>q;
    q.push(ss);
    CLR(dis,-1);
    dis[ss]=0;
    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(edge[i].w&&dis[v]<0)
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return dis[tt]>0;
}
//int bfs() //居然比STL慢10多ms
//{
//    int first=0,tail=0;
//    q[tail++]=ss;
//    CLR(dis,-1);
//    dis[ss]=0;
//    while(first<tail)
//    {
//        int u=q[first++];
//        for(int i=head[u];i!=-1;i=edge[i].next)
//        {
//            int v=edge[i].v;
//            if(edge[i].w && dis[v]<0)
//            {
//                dis[v]=dis[u]+1;
//                q[tail++]=v;
//            }
//        }
//    }
//    return dis[tt]>0;
//}

int dfs(int u,int low)
{
    int flow;
    if(u==tt)   return low;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        if(edge[i].w
        && (dis[edge[i].v]==dis[u]+1)
        && (flow = dfs(edge[i].v,min(low,edge[i].w)))){
            edge[i].w-=flow;
            edge[i^1].w+=flow;
            return flow;
        }
    }
    dis[u]=-1;
    return 0;
}
int maxFlow()
{
    int ans=0,tans;
    while(bfs())
        while(tans=dfs(ss,inf))
            ans+=tans;
    return ans;
}
int main()
{
//    RE
    int n,f,d,tw;
    char s1[205];
    char ch;
    while(scanf("%d%d%d",&n,&f,&d)!=EOF)
    {
        init();
        ss=0,tt=2*n+f+d+1;
        FOR(i,1,f)  //food:1-f
        {
            scanf("%d",&tw);
            addEdge(ss,i,tw);
        }

        FOR(i,1,d)  //drink:1+f+2*n ~ d+f+2*n
        {
            scanf("%d",&tw);
            addEdge(i+f+2*n,tt,tw);
        }

        FOR(i,1,n)
        {
            scanf("%s",s1);
            FOR(j,1,f)
            {
                if(s1[j-1]=='Y'){
                    addEdge(j,f+i,1);   //food:1~n people1:f+1~f+n
                }
            }
            addEdge(i+f,i+f+n,1);
        }
        FOR(i,1,n)
        {
            scanf("%s",s1);
            FOR(j,1,d)
            {
                if(s1[j-1]=='Y')
                    addEdge(i+f+n,j+f+2*n,1);   //people2:f+n+1~f+n+n drink:f+d+2*n+1~f+d+2*n+d
            }
        }
        printf("%d\n",maxFlow());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值