网络流 poj 3436 poj 3281

poj 3436

一个电脑有p个部分  n 台机器

n 个机器  每个机器 最多能服务的电脑数目 电脑进来时候需要的  0 代表一定不要 1 一定要 2可有可无    然后就是出去的电脑  0 代表没的   1代表有

超级源点   p 部分没有1    出来的满足进去的条件   都是1      汇点 

 0   权             两点连 权值是小的         权   n+1

跑一下Dinic

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>

using namespace std;

#define MAXN 100
#define inf  1000000000

int head[MAXN];
int z[MAXN],cnt,in[MAXN][15],out[MAXN][15],an[MAXN][MAXN],enu[MAXN*3],env[MAXN*3],enw[MAXN*3];
struct edg
{
    int fr,to,next,w;
}edge[300000];

void add(int u,int v,int w)
{
    edge[cnt].fr=u;
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    edge[cnt].w=w;
    head[u]=cnt++;
}
int st,en;
int vis[MAXN];
queue<int>q1;
bool bfs()
{
    memset(vis,-1,sizeof(vis));
    vis[st]=0;
    q1.push(st);
    while(!q1.empty())
    {
        int now = q1.front();
        q1.pop();
        for(int i=head[now];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(vis[v]<0&&edge[i].w)
            {
                vis[v]=vis[now]+1;
                q1.push(v);
            }
        }
    }
    return vis[en]!=-1;
}
int dfs(int u,int w)
{
    if(u==en)
        return w;
    int ans=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if((vis[v]==vis[u]+1)&&edge[i].w)
        {
            int b=dfs(v,min(w-ans,edge[i].w));
            edge[i].w-=b;
            edge[i^1].w+=b;
            an[u][v]+=b;
            an[v][u]-=b;
            ans += b;
        }
    }
    return ans;
}
int main()
{
    int p,n;
    scanf("%d%d",&p,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&z[i]);
        for(int j=1;j<=p;j++)
            scanf("%d",&in[i][j]);
        for(int j=1;j<=p;j++)
            scanf("%d",&out[i][j]);
    }
    st =0;
    en =n+1;
    cnt=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        int ok=0;
        for(int j=1;j<=p;j++)
            if(in[i][j]==1)
                ok=1;
        if(ok==0)
        {
            add(st,i,z[i]);
            add(i,st,0);
        }
        ok=0;
        for(int j=1;j<=p;j++)
            ok+=out[i][j];
        if(ok==p)
        {
            add(i,en,z[i]);
            add(en,i,0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)
                continue;
            //进去出来建边
            int ok=0;
            for(int k=1;k<=p;k++)
                if(out[i][k]+in[j][k]==1)
                    ok=1;
            if(ok==0)
            {
                add(i,j,min(z[i],z[j]));
                add(j,i,0);
            }
        }
    }
    int ans=0;
    while(bfs())
        ans += dfs(st,inf);
    if(ans==0)
        printf("0 0
");
    else
    {
        int cn=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(an[i][j]>0)
                {
                    enu[cn]=i;
                    env[cn]=j;
                    enw[cn]=an[i][j];
                    cn++;
                }
        printf("%d %d
",ans,cn);
        for(int i=0;i<cn;i++)
            printf("%d %d %d
",enu[i],env[i],enw[i]);
    }
    return 0;
}
View Code

n 个牛 F个吃的   D个喝的

一个牛 只能有1个吃的和喝的  一个吃的 只能给一个牛  喝的也是

问 多少牛 有吃的也有喝的 

一开始 建图 超级原点  吃的   牛  喝的 超级汇点  

结果 GG了  因为这样 有2个吃的  2个喝的 都满足牛  答案是2 

所以 牛要拆一下 超级源点   吃的      牛  牛     喝的  超级汇点

权值            1    条件+权值  1  条件+权值  1

#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>

using namespace std;

#define MAXN 410
#define inf  1000000000

int head[MAXN];
int cnt,S,T;
struct edg
{
    int to,w,next;
}edge[200000];
void add(int u,int to,int w)
{
    edge[cnt].to=to;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
queue<int>q1;
int vis[MAXN];

bool bfs()
{
    memset(vis,-1,sizeof(vis));
    vis[S]=0;
    q1.push(S);
    while(!q1.empty())
    {
        int now=q1.front();
        q1.pop();
        for(int i=head[now];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(vis[v]<0&&edge[i].w)
            {
                vis[v]=vis[now]+1;
                q1.push(v);
            }
        }
    }
    return vis[T]!=-1;
}
int dfs(int u,int w)
{
    if(u==T)
        return w;
    int ans=0;

    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if((vis[v]==vis[u]+1)&&edge[i].w)
        {
            int b=dfs(v,min(edge[i].w,w-ans));
            edge[i].w-=b;
            edge[i^1].w+=b;
            ans += b;
        }
    }
    //printf("%d
",ans);
    return ans;
}
int main()
{
    int n,f,d;
    scanf("%d%d%d",&n,&f,&d);
    memset(head,-1,sizeof(head));
    cnt=0;
    S=0;
    T=n*2+f+d+1;
    for(int i=1;i<=f;i++)
    {
        add(S,i,1);
        add(i,S,0);
    }
    for(int i=n*2+f+1;i<=n*2+f+d;i++)
    {
        add(i,T,1);
        add(T,i,0);
    }
    for(int i=f+1;i<=n+f;i++)
    {
        add(i,i+n,1);
        add(i+n,i,0);
    }
    for(int i=1;i<=n;i++)
    {
        int f1,d1;
        scanf("%d%d",&f1,&d1);
        for(int j=1;j<=f1;j++)
        {
            int a;
            scanf("%d",&a);
            add(a,i+f,1);
            add(i+f,a,0);
        }
        for(int j=1;j<=d1;j++)
        {
            int a;
            scanf("%d",&a);
            add(i+f+n,a+n*2+f,1);
            add(a+n*2+f,i+f+n,0);
        }
    }
    int ans=0;
    while(bfs())
        ans += dfs(S,inf);
    printf("%d
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/cherryMJY/p/6545097.html