poj3436(拆点最大流)

题意:给你p和n,p代表每台计算器需要几个部分组成,n代表有几个组装机器,接下来n行,每行第一个数代表这台机器能够每小时组装几台,剩下前三个数字表示使用这台机器需要的前置条件(0代表当前组装不能有这个部分,1代表得有,2代表无所谓),剩下三个数字表示使用这台机器后的组装有那几个部分,问你最多能组装多少台

解题思路:首先最大流,建立一个超级源点,这个源点和所有前三个数字没有1的机器相连,建立一个超级汇点与所有后三个数字全为1的机器相连,中间所有的机器拆成两个点,边权为这个机器每小时的组装量,拆点的意义就是因为流过这个点的流量有限制

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5050;
struct sc
{
    int x,y,w;
}fna[maxn];
struct node
{
    int val;
    int x[15];
    int y[15];
}a[100];
struct Edge
{
    int fa;
    int next;
    int to;
    int v;
    int w;
}edge[maxn];
int head[maxn],cnt;
int pre[maxn],visit[maxn];
int n,p,cot;
int Start,End;
void add(int u,int v,int w)
{
    edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].fa=u;edge[cnt].w=w;head[u]=cnt++;
    edge[cnt].next=head[v];edge[cnt].to=u;edge[cnt].fa=v;edge[cnt].w=0;head[v]=cnt++;
}
int bfs(int s,int e)
{
    queue<int>q;
    memset(visit,0,sizeof(visit));memset(pre,-1,sizeof(pre));
    q.push(s);visit[s]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(edge[i].w<=0||visit[v])
                continue;
            pre[v]=i;visit[v]=1;
            if(v==e)
                return 1;
            q.push(v);
        }
    }
    return 0;
}
int EK()
{
    int ans=0;
    int sub;
    while(bfs(Start,End))
    {
        sub=inf;
        int k=pre[End];
        while(k!=-1)
        {
            sub=min(sub,edge[k].w);
            k=pre[edge[k].fa];
        }
        k=pre[End];
        while(k!=-1)
        {
            edge[k].w-=sub;
            edge[k^1].w+=sub;
            k=pre[edge[k].fa];
        }
        ans+=sub;
    }
    return ans;
}
int main()
{
    int vis[150][150];
    int flag;
    memset(head,-1,sizeof(head));cnt=0;
    memset(vis,0,sizeof(vis));
    scanf("%d%d",&p,&n);
    Start=0;End=2*n+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].val);
        for(int j=1;j<=p;j++)
            scanf("%d",&a[i].x[j]);
        for(int j=1;j<=p;j++)
            scanf("%d",&a[i].y[j]);
    }
    for(int i=1;i<=n;i++)
    {
        add(i,i+n,a[i].val);
        flag=0;
        for(int j=1;j<=p;j++)
            if(a[i].x[j]==1)
                flag=1;
        if(flag==0)
            add(Start,i,a[i].val);
        flag=0;
        for(int j=1;j<=p;j++)
            if(a[i].y[j]!=1)
                flag=1;
        if(flag==0)
            add(i+n,End,a[i].val);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
    {
        flag=0;
        if(i==j)
            continue;
        for(int k=1;k<=p;k++)
        {
            if(a[j].x[k]==2)
                continue;
            if(a[j].x[k]!=a[i].y[k])
                flag=1;
        }
        if(flag==0)
        {
            add(i+n,j,a[i].val);
            vis[i+n][j]=1;
        }
    }
    int ans=EK();
    printf("%d ",ans);
    for(int i=1;i<=n;i++)
        for(int j=head[i+n];j!=-1;j=edge[j].next)
    {
        if(vis[i+n][edge[j].to]&&edge[j].w<a[i].val)
            cot++;
    }
    printf("%d\n",cot);
    for(int i=1;i<=n;i++)
        for(int j=head[i+n];j!=-1;j=edge[j].next)
    {
        if(vis[i+n][edge[j].to]&&edge[j].w<a[i].val)
            printf("%d %d %d\n",i,edge[j].to,a[i].val-edge[j].w);
    }
}

  

posted @ 2018-11-13 22:35  荒岛的龟  阅读(230)  评论(0编辑  收藏  举报