POJ 3436 ACM Computer Factory

84 篇文章 0 订阅
12 篇文章 0 订阅

这题的题目内容读起来很复杂,我来简单解释一下:


        为了追求ACM比赛的公平性,所有用作ACM比赛的电脑性能是一样的,而ACM董事会专门有一条生产线来生产这样的电脑,随着比赛规模的越来越大,生产线的生产能力不能满足需要,所以说ACM董事会想要重新建造一条生产线。


        生产线是全自动化的,所以需要机器来组成生产线,给定有多少中种机器,标准ACM用电脑有多少部份,每种机器将什么样的ACM电脑半成品处理成什么样的电脑半成品(对于输入的电脑半成品,每部分有0,1,2三种状态:代表着 0、这部分必须没有我才能处理,1、这部分必须有我才能处理,2、这部分有没有我都能处理。对于输出的电脑半成品有0,1两种状态:代表着0,处理完后的电脑半成品里没有这部分,1、处理完的电脑半成品有这部分),每一个机器每小时可以处理Q个半成品(输入数据中的Qi)。


        求组装好的成产线的最大工作效率(每小时最多生成多少成品,成品的定义就是所有部分的状态都是“1”),和每两个机器之间的流量。


因为是Special Judge,所以对边的输出顺序没有要求(好像Discuss里有的数据过不去也AC了,这是什么情况?)。


这是一个不定源点和汇点的最大流问题,因为我们不能控制输入数据中用多少个输入状态全是"0"的机器,也不知道有多少个输出状态全是“1”的机器,所以我们需要虚拟一个超级源点和超级汇点来解决他们。


然后根据特征建图,EK算法,最后处理输出……


下面是代码:

#include <stdio.h>
#include <string.h>
#include <queue>

using namespace std;
struct node
{
    int in[12],out[12],ro;
}machine[55];
const int inf = 1<<30;
const int M =55;
int map1[M][M],pre[M],vis[M],n;
int min(int a,int b)
{
    return a>b?b:a;
}
int EK()
{
    int i,ans=0,now,min1;
    queue <int> q;
    while(1)  //每循环一次找一次增广路
    {
        memset(pre,-1,sizeof(pre));
        memset(vis,0,sizeof(vis));
        while(!q.empty())
        {
            q.pop();
        }
        q.push(0);
        vis[0]=1;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            if(now==n+1) //已经搜索到超级汇点  跳出循环
            {
                break;
            }
            for(i=0;i<=n+1;i++)
            {
                if(!vis[i]&&map1[now][i]>0)//如果节点i没被搜索过且节点now到节点i残余流量大于0
                {
                    pre[i]=now; //记录i的前驱节点是now
                    vis[i]=1;  //标记i点已经被访问过
                    q.push(i);  //把i点放入队列进行下一次BFS
                }
            }
        }
        if(!vis[n+1])
        {
            break;  //如果BFS完毕没有搜到到节点n+1的增广路,就已经找到最大流  跳出
        }
        min1=inf;
        for(i=n+1;i!=0;i=pre[i])
        {
            if(map1[pre[i]][i]<min1)  //寻找整个增广路上的残余流量的最小值,此为整个增广路的流量
            {
                min1=map1[pre[i]][i];
            }
        }
        ans+=min1;
        for(i=n+1;i!=0;i=pre[i])
        {
            map1[pre[i]][i]-=min1;//残余流量减少
            map1[i][pre[i]]+=min1;//已使用流量增加
        }
    }
    return ans;
}
int main()
{
    int p,backup[M][M],flat,an,i,j,k;
    while(scanf("%d%d",&p,&n)!=EOF)
    {
        int cut=0,ji[M][3];
        for(i=1;i<=n;i++)//输入部分
        {
            scanf("%d",&machine[i].ro);
            for(j=0;j<p;j++)
            {
                scanf("%d",&machine[i].in[j
            }
            for(j=0;j<p;j++)
            {
                scanf("%d",&machine[i].out[j]);
            }
        }
        memset(map1,0,sizeof(map1));
        for(i=1;i<=n;i++)
        {
            int fs=1,ft=1;
            for(j=0;j<p;j++)
            {
                if(machine[i].in[j]==1)  //判断其是能否和超级源点相连
                {
                    fs=0;
                }
                if(machine[i].out[j]==0)  //判断其能否和超级汇点相连
                {
                    ft=0;
                }
            }
            if(fs)
            {
                map1[0][i]=machine[i].ro;
            }
            if(ft)
            {
                map1[i][n+1]=machine[i].ro;
            }
            for(j=1;j<=n;j++)//判断其能否和其他点相连
            {
                if(i!=j)
                {
                    flat=1;
                    for(k=0;k<p;k++)
                    {
                        if(machine[i].out[k]+machine[j].in[k]==1)
                        {
                            flat=0;
                            break;
                        }
                    }
                    if(flat)
                    {
                        map1[i][j]=min(machine[i].ro,machine[j].ro);
                    }
                }
            }
        }
        memcpy(backup,map1,sizeof(map1));  //做一个数据备份用来最后的时候比较用
        an=EK();
        for(i=1;i<=n;i++)  //注意范围   超级源点和超级汇点是我们自己虚拟出来的,其实并不存在
        {
            for(j=1;j<=n;j++)
            {
                if(backup[i][j]>map1[i][j])
                {
                    ji[cut][0]=i;
                    ji[cut][1]=j;
                    ji[cut][2]=backup[i][j]-map1[i][j];
                    cut++;
                }
            }
        }
        printf("%d %d\n",an,cut);//输出
        for(i=0;i<cut;i++)
        {
            printf("%d %d %d\n",ji[i][0],ji[i][1],ji[i][2]);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值