网络流_最大流_POJ 3281

题目链接:http://poj.org/problem?id=3281

个人认为这个题的难点就在于见图,应为有多个源点和起点,所以我们可以设置一个超级源点和超级汇点

将牛分1为2,一个牛吃菜,一个牛吃草,两个牛之间一一对应,之间的容量都是1


所以总的节点的个数就是2*n+f+d+2

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#define MAXINT INT_MAX
using namespace std;
const int MAX_N = 500;
const int INF = 100000000;
class edge
{
public:

    int flow;//流量
    int cap;//容量
    edge(int flow,int cap) : flow(flow),cap(cap){}
    edge()
    {
        flow =0;
        cap=0;
    }
};
edge maps[MAX_N][MAX_N];
int dis[MAX_N];//用于分成

int n,f,d,totaln;
int s,t;

//参数是源点和汇点
bool bfs(int s,int t)
{
    int v,i;
    queue<int> que;
    memset(dis,0,sizeof(dis));
    que.push(s);
    dis[s] =1;
    while(!que.empty())
    {
        v = que.front();
        que.pop();
        for(int i=1;i<=totaln;i++)
        {
            if(!dis[i] && maps[v][i].cap>maps[v][i].flow)
            {
                que.push(i);//该点的流量还是可以增加的
                dis[i] = dis[v] +1;
            }
        }
        //到达终点
        if( v==t )
            return true;
    }
    return false;

}


int dfs(int s,int t,int f)
{
    if(s==t)
        return f;
    int temp = f;
    int d;
    for(int i=1;i<=totaln;i++)
    {
        if(dis[i]==(dis[s]+1) && temp && maps[s][i].cap>maps[s][i].flow)
        {
            d = dfs(i,t,min(temp,maps[s][i].cap-maps[s][i].flow));
           // cout<<d<<endl;
            maps[s][i].flow += d;
            maps[i][s].flow -= d;
            temp -= d;
        }
    }
    return f-temp;
}

int dinic(int s,int t)
{
    int maxflow = 0;
    while(bfs(s,t))
    {
        //cout<<maxflow<<endl;
        maxflow += dfs(s,t,INF);
    }
    return maxflow;
}

//代表奶牛数,菜的数目,汤的数目
void build_graph(int n,int f,int d)
{
    totaln = 2*n+f+d+2;
    s = 2*n+f+d+1;//源点
    t = 2*n+f+d+2;//汇点

   // cout<<s<<" "<<t<<endl;
    for(int i=1;i<=f;i++)
    {
        //源点指向食物
        maps[s][i].cap=1;
    }

    for(int i=1;i<=d;i++)
    {
        //饮料指向汇点
        maps[2*n+f+i][t].cap=1;
    }
    int lf,ld;//喜欢菜的种类数和烫的种类数
    for(int i=1;i<=n;i++)
    {
        //第i头牛

        //第第一类牛的第i个指向第二类牛的第i个,可以防止一个牛吃多种食物
        maps[f+i][f+i+n].cap=1;

        scanf("%d %d",&lf,&ld);
        int lff,ldd;//喜欢菜和汤的编号
        for(int j = 1;j<=lf;j++)
        {
            //s食物指向第一类牛
            scanf("%d",&lff);
            maps[lff][i+f].cap=1;

        }
        for(int j=1;j<=ld;j++)
        {
            //由第二类牛指向drink
            scanf("%d",&ldd);
            maps[i+f+n][n+f+n+ldd].cap=1;
        }
    }

}

int main()
{
    //freopen("最大流_POJ_3281.txt","r",stdin);
    while(scanf("%d %d %d",&n,&f,&d)!=EOF)
    {
        build_graph(n,f,d);
        printf("%d\n",dinic(s,t));
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值