POJ 3281 网络流(dinic邻接矩阵、单路增广、多路增广)

思路:刚开始看题就想到怎么建图了,源点连向所有的食物,食物连牛,牛连饮料,饮料连汇点,所有的流量都是1.不过这样建图好后,WA了。原来是一头牛只能单一匹配一组食物和饮料,所以牛得拆点,牛之间得相连,流量为1,以保证单一匹配食物和饮料。

邻接矩阵dinic单路的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 20005
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,m,d[maxn],Map[501][501];
int bfs()
{
    mem(d,-1);
    queue<int>q; q.push(0); d[0]=0;
    while(!q.empty())  //找增广路
    {
        int u=q.front(); q.pop();
        for(int v=0;v<=n;v++)
        {
            if(d[v]==-1&&Map[u][v])
            {
                d[v]=d[u]+1; //分层,越往后,层数越大
                q.push(v);
            }
        }
    }
    return d[n]!=-1;
}
int dfs(int u,int Min)
{
    int sum;
    if(u==n) return Min;
    for(int v=0;v<=n;v++)
        if(Map[u][v]&&d[v]==d[u]+1&&(sum=dfs(v,min(Min,Map[u][v]))))
        {
            Map[u][v]-=sum;
            Map[v][u]+=sum;
            return sum;
        }
    return 0;
}
int Dinic()
{
    int tmp,ans=0;
    while(bfs())
    {
        while(tmp=dfs(0,INF))
            ans+=tmp;
    }
    return ans;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int N,F,D,ff,dd,i,j,mm;
    scanf("%d%d%d",&N,&F,&D);
    for(i=1;i<=N;i++)
    {
        scanf("%d%d",&ff,&dd);
        for(j=0;j<ff;j++)
        {
            scanf("%d",&mm);
            Map[mm+N*2][i]=1;
        }
        for(j=0;j<dd;j++)
        {
            scanf("%d",&mm);
            Map[i+N][mm+N*2+F]=1;
        }
        Map[i][i+N]=1;//牛之间自连,保存每头牛只匹配一组食物和饮料
    }
    for(i=N*2+1;i<=N*2+F;i++)
        Map[0][i]=1;//连源点
    n=N*2+F+D+1;
    for(i=N*2+F+1;i<=N*2+F+D;i++)
        Map[i][n]=1;//连汇点
    printf("%d\n",Dinic());
    return 0;
}

dinic单路增广代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
#define maxn 2000005
int n,cnt,d[maxn],head[maxn],go[maxn],q[maxn];
struct node
{
    int v,w,next;
}e[maxn];
void add(int u,int v,int w)
{
    e[cnt].v=v; e[cnt].w=w; go[cnt]=cnt+1;
    e[cnt].next=head[u]; head[u]=cnt++;
    e[cnt].v=u; e[cnt].w=0; go[cnt]=cnt-1;//刚开始反向边权值写成w了一直wa
    e[cnt].next=head[v]; head[v]=cnt++;
}
int bfs()
{
    mem(d,-1);
    int l=0,r=0;
    q[r++]=0; d[0]=0;
    while(l<r)  //找增广路
    {
        int u=q[l++];
        for(int v=head[u];v!=-1;v=e[v].next)
        {
            if(d[e[v].v]==-1&&e[v].w)
            {
                d[e[v].v]=d[u]+1; //分层,越往后,层数越大
                if(e[v].v!=n+1) q[r++]=e[v].v;
            }
        }
    }
    return d[n]!=-1;
}
int dfs(int u,int Min)
{
    int sum;
    if(u==n) return Min;
    for(int v=head[u];v!=-1;v=e[v].next)  //Min-duolu这个多路增广的做法真神!
        if(e[v].w&&d[e[v].v]==d[u]+1&&(sum=dfs(e[v].v,min(Min,e[v].w))))
        {
            e[v].w-=sum;
            e[go[v]].w+=sum;
            return sum;
        }
    return 0;
}
void init()
{
    mem(head,-1),mem(go,0),cnt=0;
}
int Dinic()
{
    int tmp,ans=0;
    while(bfs())
    {
        while(tmp=dfs(0,INF)) ans+=tmp;
    }
    return ans;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int N,F,D,ff,dd,i,j,mm;
    scanf("%d%d%d",&N,&F,&D);
    init();
    for(i=1;i<=N;i++)
    {
        scanf("%d%d",&ff,&dd);
        for(j=0;j<ff;j++)
        {
            scanf("%d",&mm);
            add(mm+N*2,i,1);
        }
        for(j=0;j<dd;j++)
        {
            scanf("%d",&mm);
            add(i+N,mm+N*2+F,1);
        }
        add(i,i+N,1);//牛之间自连,保存每头牛只匹配一组食物和饮料
    }
    for(i=N*2+1;i<=N*2+F;i++)
        add(0,i,1);//连源点
    n=N*2+F+D+1;
    for(i=N*2+F+1;i<=N*2+F+D;i++)
        add(i,n,1);//连汇点
    printf("%d\n",Dinic());
    return 0;
}

Dinic多路增广代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
#define maxn 2000005
int n,cnt,d[maxn],head[maxn],go[maxn],q[maxn];
struct node
{
    int v,w,next;
}e[maxn];
void add(int u,int v,int w)
{
    e[cnt].v=v; e[cnt].w=w; go[cnt]=cnt+1;
    e[cnt].next=head[u]; head[u]=cnt++;
    e[cnt].v=u; e[cnt].w=0; go[cnt]=cnt-1;//刚开始反向边权值写成w了一直wa
    e[cnt].next=head[v]; head[v]=cnt++;
}
int bfs()
{
    mem(d,-1);
    int l=0,r=0;
    q[r++]=0; d[0]=0;
    while(l<r)  //找增广路
    {
        int u=q[l++];
        for(int v=head[u];v!=-1;v=e[v].next)
        {
            if(d[e[v].v]==-1&&e[v].w)
            {
                d[e[v].v]=d[u]+1; //分层,越往后,层数越大
                if(e[v].v!=n+1) q[r++]=e[v].v;
            }
        }
    }
    return d[n]!=-1;
}
int dfs(int u,int Min)
{
    int sum,duolu=0;
    if(u==n) return Min;
    for(int v=head[u];v!=-1&&Min-duolu>0;v=e[v].next)  //Min-duolu这个多路增广的做法真神!
        if(e[v].w&&d[e[v].v]==d[u]+1&&(sum=dfs(e[v].v,min(Min-duolu,e[v].w))))
        {
            e[v].w-=sum;
            e[go[v]].w+=sum;
            duolu+=sum;
        }
    return duolu;
}
void init()
{
    mem(head,-1),mem(go,0),cnt=0;
}
int Dinic()
{
    int tmp,ans=0;
    while(bfs())
    {
        while(tmp=dfs(0,INF)) ans+=tmp;
    }
    return ans;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int N,F,D,ff,dd,i,j,mm;
    scanf("%d%d%d",&N,&F,&D);
    init();
    for(i=1;i<=N;i++)
    {
        scanf("%d%d",&ff,&dd);
        for(j=0;j<ff;j++)
        {
            scanf("%d",&mm);
            add(mm+N*2,i,1);
        }
        for(j=0;j<dd;j++)
        {
            scanf("%d",&mm);
            add(i+N,mm+N*2+F,1);
        }
        add(i,i+N,1);//牛之间自连,保存每头牛只匹配一组食物和饮料
    }
    for(i=N*2+1;i<=N*2+F;i++)
        add(0,i,1);//连源点
    n=N*2+F+D+1;
    for(i=N*2+F+1;i<=N*2+F+D;i++)
        add(i,n,1);//连汇点
    printf("%d\n",Dinic());
    return 0;
}
时间: 2024-08-30 05:21:27

POJ 3281 网络流(dinic邻接矩阵、单路增广、多路增广)的相关文章

POJ 3281 网络流dinic算法

B - Dining Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3281 Appoint description: Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she wil

POJ 3281 网络流 拆点保证本身只匹配一对食物和饮料

如何建图? 最开始的问题就是,怎么表示一只牛有了食物和饮料呢? 后来发现可以先将食物与牛匹配,牛再去和饮料匹配,实际上这就构成了三个层次. 起点到食物层边的容量是1,食物层到奶牛层容量是1,奶牛层到饮料层容量是1,饮料层到终点容量是1. 但是后来发现有一组hack数据: 2 3 3 3 3 1 2 3 1 2 3 3 3 1 2 3 1 2 3 我们发现一头奶牛居然吃了多个套餐,所以要解决这个只需要将自己与自己建立一条容量是1的边就行了. #include <cstdio> #include

B - Dining POJ - 3281 网络流

Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others. Farmer John has cooked fabulous meals for his cows, but he forgot to check his menu against their preferences. Although he might not

POJ 3281 网络流 拆点 Dining

题意: 有F种食物和D种饮料,每头牛有各自喜欢的食物和饮料,而且每种食物或者饮料只能给一头牛. 求最多能有多少头牛能同时得到它喜欢的食物或者饮料. 分析: 把每个牛拆点,中间连一条容量为1的边,保证一头牛不会被多个食物或者饮料分配. 然后把饮料和牛连边,食物和另外一边的牛连边,最后增加一个源点和汇点跑最大流. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <alg

poj 1149 PIGS(网络流dinic)

PIGS Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16054   Accepted: 7185 Description Mirko works on a pig farm that consists of M locked pig-houses and Mirko can't unlock any pighouse because he doesn't have the keys. Customers come t

POJ 1273 Drainage Ditches (网络流Dinic模板)

Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage

网络流Dinic(本篇介绍最大流)

前言:看到网上Dinic和ISAP的比较,多数人认为ISAP更快,不容易爆栈.当然,也有少数人认为,在多数情况下,Dinic比较稳定.我认为Dinic的思路比ISAP更简明,所以选择了Dinc算法 介绍:Dinic算法本身,自然是解决最大流(普通最大流,最大流最小割)的算法.通过处理,也可以解决二分图的最大匹配(下文介绍),最大权闭合图. 算法介绍:介绍Dinic之前,我们先介绍一下最大流.在最大流的题目中,图被称为"网络",每条边的边权被称作"流量",有一个起点(

POJ 3281 Dining(网络最大流)

http://poj.org/problem?id=3281 Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9121   Accepted: 4199 Description Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will consume no others.

POJ 3281 Dining(最大流)

POJ 3281 Dining 题目链接 题意:n个牛,每个牛有一些喜欢的食物和饮料,每种食物饮料只有一个,问最大能匹配上多少只牛每个牛都能吃上喜欢的食物和喜欢的饮料 思路:最大流,建模源点到每个食物连一条边,容量为1,每个饮料向汇点连一条边容量为1,然后由于每个牛有容量1,所以把牛进行拆点,然后食物连向牛的入点,牛的出点连向食物,跑一下最大流即可 代码: #include <cstdio> #include <cstring> #include <queue> #in