您的位置:首页 > 其它

POJ 3436 ACM Computer Factory

2013-08-13 10:12 507 查看
这题的题目内容读起来很复杂,我来简单解释一下:

为了追求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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: