poj 3436 ACM Computer Factory 最大流拆点+输出路径

题目链接:

poj3436





题意:

每台ACM 计算机包括P 个部件。当全部这些部件都准备齐全后,计算机就能够组装了。组装好以后就能够交给竞赛队伍使用了。

计算机的生产过程是全自己主动的,通过N 台不同的机器来完毕。

每台机器从一台半成品计算机中去掉一些部件。并增加一些新的部件(去除一些部件在有的时候是必须的,由于计算机的部件不能以随意的顺序组装)。

每台机器用它的性能(每小时组装多少台计算机)、输入/输出规格来描写叙述。

输入规格描写叙述了机器在组装计算机时哪些部件必须准备好了。输入规格是由P 个整数组成。每一个整数代表一个部件。这些整数取值为0, 1 或2,当中0 表示该部件不应该已经准备好了。1表示该部件必须已经准备好了。2 表示该部件是否已经准备好了无关紧要。

输出规格描写叙述了该机器组装的结果。

输出规格也是由P 个整数组成,每一个整数取值为0 或1,当中0 代表该部件没有生产好,1 代表该部件生产好了。

机器之间用传输速度很快的流水线连接。部件在机器之间传送所需的时间与机器生产时间相比是十分小的。

给出上述关于n台机器的描写叙述,求一小时最多组成多少台计算机,并输出流水线的路径



解题思路:

题目已给出条件:  机器之间传输不须要时间,也就能够理解为流水线上每台机器的工作都是同步的,这样就能够用网络流来攻克了(单位时间问题)

解题的关键在于建图.

话不多说,给出一张例子图:

图中红色边的容量应设为无穷大(单位时间运输无限台计算机)

值得注意的是  图中两台机器的连接能够是双向的(比方能够同一时候又B1->A2 ,B2->A1 )

关于路径的输出(找从n+1~2*n)開始的正向边,有流则表示生产线经过这条路径




代码:

#include <iostream>
#include <cstring>
#include<cstdio>
#define LL long long
#include <queue>
const int MAXN =205;
const int MAXM=440020;
const int INF=0x3f3f3f3f;
using namespace std;
struct Edge
{
    int from;
    int to,cap,flow,next;
} edge[MAXM];
int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];

void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int c,int f)
{
    edge[tot]=(Edge)
    {
        u,v,c,f,head[u]
    };
    head[u] = tot++;
    edge[tot]=(Edge)
    {
        v,u,c,c,head[v]
    };
    head[v] = tot++;
}

int isap(int source,int sink,int N)
{
    memset(gap,0,sizeof(gap));
    memset(d,0,sizeof(d));
    memcpy(cur,head,sizeof(head));
    int top = 0,x = source,flow = 0;
    while(d[source] < N)
    {
        if(x == sink)
        {
            int Min = INF,inser=0;
            for(int i = 0; i < top; ++i)
            {
                if(Min > edge[p[i]].cap - edge[p[i]].flow)
                {
                    Min = edge[p[i]].cap - edge[p[i]].flow;
                    inser = i;
                }
            }
            for(int i = 0; i < top; ++i)
            {
                edge[p[i]].flow += Min;
                edge[p[i]^1].flow -= Min;
            }
            if(Min!=INF) flow += Min;
            top = inser;
            x = edge[p[top]^1].to;
            continue;
        }
        int ok = 0;
        for(int i = cur[x]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow && d[v]+1 == d[x])
            {
                ok = 1;
                cur[x] = i;
                p[top++] = i;
                x = edge[i].to;
                break;
            }
        }
        if(!ok)
        {
            int Min = N;
            for(int i = head[x]; i != -1; i = edge[i].next)
            {
                if(edge[i].cap > edge[i].flow && d[edge[i].to] < Min)
                {
                    Min = d[edge[i].to];
                    cur[x] = i;
                }
            }
            if(--gap[d[x]] == 0) break;
            gap[d[x] = Min+1]++;
            if(x != source) x = edge[p[--top]^1].to;
        }
    }
    return flow;
}

int state[MAXN][2][10];
int pp,n;

int equall(int x,int y)
{
    for(int i=0;i<pp;i++)
        if(state[y][0][i]+state[x][1][i]==1)
            return 0;

    return 1;
}
int main()
{
//    freopen("in.txt","r",stdin);
    int w,flag1,flag2;
    while(~scanf("%d%d",&pp,&n))
    {
        init();
        memset(state,0,sizeof(state));

        for(int i=1;i<=n;i++)
        {
            flag1=flag2=1;
            scanf("%d",&w);
            for(int j=0;j<pp;j++){      //全是0或2 则连接源点
                scanf("%d",&state[i][0][j]);
                if(state[i][0][j]==1)
                    flag1=0;
            }

            for(int j=0;j<pp;j++){       //全是1 则连接汇点
                scanf("%d",&state[i][1][j]);
                if(state[i][1][j]==0||state[i][1][j]==2)
                    flag2=0;
            }

            addedge(i,i+n,w,0);          //拆点连自己

            if(flag1==1)
                addedge(0,i,INF,0);
            if(flag2==1)
                addedge(i+n,2*n+1,INF,0);

            for(int j=1;j<i;j++){
                if(equall(i,j))
                    addedge(n+i,j,INF,0);
                if(equall(j,i))           //注意不能是else if 两个机器能够是双向连接的
                    addedge(n+j,i,INF,0);
            }
        }

        printf("%d",isap(0,2*n+1,2*n+2));

        int ans[400][3];
        int ss=0;
        for(int i=n+1;i<=(n<<1);i++)      //邻接表找最大流中的边
            for(int j=head[i];j!=-1;j=edge[j].next)
            {
                if(edge[j].to==2*n+1||edge[j].to==i-n)
                    continue;
                if(edge[j].flow>0){
                    ans[ss][0]=edge[j].from-n;
                    ans[ss][1]=edge[j].to;
                    ans[ss++][2]=edge[j].flow;
                }
            }
        printf(" %d\n",ss);
        for(int i=0;i<ss;i++)
            printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
    }
    return 0;
}



转载于:https://www.cnblogs.com/ljbguanli/p/6861241.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值