poj3436 ACM Computer Factory

题意:一家公司有n台机器用来生产电脑,一个电脑有p个部分,要p个部分同时存在才算生产完成。对于一个机器,有三组数据描述。数据一:一个整数Q,用来表示机器一个小时能够加工多少电脑,数据二:(输入)p个整数,整数取值为0,1,2,用以表示电脑需满足这一组条件才能被这台机器加工。0表示这个部分不能有,1表示这个部分必须有,2表示这个部分可有可无。数据三:(输出)p个整数,整数取值为0,1。用以表示输出的电脑的状态,0表示这部分没有,1表示这部分有。可能数据二,三说得不是很清楚,举个例子:一台电脑由3个部分组成,某一台机器的数据二为(0,0,0),数据三为(1,0,1)。则表示这台机器只能加工第一部分,第二部分,第三部分均不存在的电脑,加工后这电脑有了第一部分,第三部分,缺失第二部分。然后题目要求将机器练成生产线,使得效率最大。输出还是很好理解的吧。


思路:这里我们需要建图,然后用最大流。我们将n台机器拆成2*n个点,如机器i拆成点i,和点i+n,点i表示输入,点i+n表示输出,然后我们多加两个点,源点s,汇点e。若机器i的输入全为0,则将点i与源点s相连,权值为MaxInt。若机器i的输出全为1,则将点i+n与汇点e相连,权值为MaxInt。之后再将点i与点i+n相连,权值为机器一小时加工电脑的数目Q。最后若机器i的输出与机器j的输入相等的话,则将点i+n与点j相连。建完图后,套个模板就可以了。

AC代码:

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define inf 9999999
struct data
{
    int x,y,value;
}ans[505];
int p,k;
int map[205][205];
int cnt,ca[55];
int path[505];
bool findMaxflow()
{
    bool visited[505]={0};
    memset(path,0,sizeof(path));
    queue<int> qu;
    qu.push(0); visited[0]=1;
    while(!qu.empty())
    {
        int pos = qu.front();
        qu.pop();
        if(pos==2*k+1) return 1;
        for(int i=0;i<=2*k+1;i++)
        {
            if(!visited[i]&&map[pos][i]>0)
            {
                qu.push(i);
                visited[i]=1;
                path[i]=pos;
            }
        }
    }
    return 0;
}
void modifyMap(int &add)
{
    int pos = 2*k+1;
    add = inf;
    while(pos)
    {
        if(add>map[path[pos]][pos])
        add=map[path[pos]][pos];
        pos = path[pos];
    }
    pos = 2*k+1;
    while(pos)
    {
        map[path[pos]][pos]-=add;
        map[pos][path[pos]]+=add;
        pos = path[pos];
    }
}

int main()
{

    while(scanf("%d%d",&p,&k)!=EOF)
    {
        memset(map,0,sizeof(map));
        int input[55][15],output[55][15];
        cnt=0;
        for(int i=1;i<=k;i++)
        {
            scanf("%d",&ca[i]);
            for(int j=0;j<p;j++)
            scanf("%d",&input[i][j]);
            for(int j=0;j<p;j++)
            scanf("%d",&output[i][j]);
        }

        for(int i=1;i<=k;i++)
        {
            int j;
            for(j=0;j<p;j++)
            if(output[i][j]==0) break;
            if(j>=p) map[i+k][2*k+1]=inf;

            for(j=0;j<p;j++)
            if(input[i][j]==1) break;
            if(j>=p) map[0][i]=inf;

            map[i][i+k]=ca[i];
        }

        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=k;j++)
            {
                if(i==j) continue;
                int l;
                for(l=0;l<p;l++)
                {
                    if(input[j][l]==2) continue;
                    if(output[i][l]!=input[j][l]) break;
                }
                if(l>=p) map[i+k][j]=inf;
            }
        }
        int sum=0; int add;
        while(findMaxflow())
        {
            modifyMap(add);
            sum+=add;
        }
        printf("%d ",sum);
        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=k;j++)
            {
                if(i==j) continue;
                if(map[j][i+k]>0)
                {
                    ans[cnt].x=i;
                    ans[cnt].y=j;
                    ans[cnt++].value=map[j][i+k];
                }
            }
        }
        printf("%d\n",cnt);
        for(int i=0;i<cnt;i++)
        printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].value);

    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值