poj 3281 拆点最大流

题意:一头牛需要一个食物跟一个饮料,每头牛只能选择特定的食物跟饮料,现有一定数量的食物饮料,问最多能满足几头牛


Input
Line 1: Three space-separated integers: N, F, and D
Lines 2.. N+1: Each line i starts with a two integers Fi and Di, the number of dishes that cow i likes and the number of drinks that cow i likes. The next Fi integers denote the dishes that cow i will eat, and the Di integers following that denote the drinks that cow i will drink.

Output

Line 1: A single integer that is the maximum number of cows that can be fed both food and drink that conform to their wishes



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


Sample Output
3


思路: 最大流,一头牛要满足两个条件(食物跟饮料),可以把牛放在中间来建边,将每头牛的点拆点保证只满足一次

用邻接矩阵存边,想快点的话可以改成邻接表。下标表示为 : s:0   t:401    食物:1-100   牛1:101-200  牛2:201-300  饮料:301-400;


  

#include <iostream>
using namespace std;
#include <string.h>
#include <vector>
#include <queue>

int c[405][405];  // s:0 t:401
int dep[405];
int s=0,t=401;
int const inf = 0x3f3f3f;  

int min(int a,int b)
{
	return a>b?b:a;
}

int n,f,d;    

int bfs()
{  
    queue<int> q;  
    while(!q.empty())  
        q.pop();  
    memset(dep, -1, sizeof(dep));  
    dep[s] = 0;  
    q.push(s);  
    while(!q.empty())
	{  
        int u = q.front();  
	//	cout<<u<<"  !!"<<endl;
		q.pop();  
		int v;//= u==0?1:u/100*100+101,ed=v+100;
        for( v =0; v<=401 ; v++)
		{  
            if(c[u][v] > 0 && dep[v] == -1)
			{  
                dep[v] = dep[u] + 1;  
                q.push(v);  
            }  
        }  
    }  
    return dep[t] != -1;  
}  
  
int dfs(int u, int mi, int t)
{  
    if(u == t)  
        return mi;  
    int tmp;  
	int v;//= u==0?1:u/100*100+101,ed=v+100;
    for( v=0 ; v<=401 ; v++)
	{  
        if(c[u][v] > 0 && dep[v] == dep[u] + 1  && (tmp = dfs(v, min(mi, c[u][v]), t)))
		{  
            c[u][v] -= tmp;  
            c[v][u] += tmp;  
            return tmp;  
        }  
    }  
    return 0;  
}  
  
int dinic()  
{  
    int ans = 0, tmp;  
    while(bfs())
	{  
        while(1)
		{  
            tmp = dfs(s, inf , t);  
	//		cout<<tmp<<endl;
            if(tmp == 0)  
                break;  
            ans += tmp;  
        }  
    }  
    return ans;  
}  

int main()  
{  
    while(~scanf("%d %d %d", &n, &f,&d))
	{  
        memset(c, 0, sizeof(c));  
        int u , i , j , k;
		for(i=1;i<=f;i++)
			c[s][i]=1;
		for(i=1;i<=d;i++)
			c[i+300][t]=1;
        for(k=1;k<=n;k++)
		{  
			c[k+100][k+200]=1;
			cin>>i>>j;
			while(i--)
			{				
				scanf("%d", &u);
				c[u][k+100]=1;
			}
			while(j--)
			{
				scanf("%d", &u);
				c[k+200][u+300]=1;
			}
        }  
        printf("%d\n", dinic());  
    }  
    return 0;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值