POJ 3436 ACM Computer Factory

As you know, all the computers used for ACM contests must be identical, so the participants compete on equal terms. That is why all these computers are historically produced at the same factory.

Every ACM computer consists of P parts. When all these parts are present, the computer is ready and can be shipped to one of the numerous ACM contests.

Computer manufacturing is fully automated by using N various machines. Each machine removes some parts from a half-finished computer and adds some new parts (removing of parts is sometimes necessary as the parts cannot be added to a computer in arbitrary order). Each machine is described by its performance (measured in computers per hour), input and output specification.

Input specification describes which parts must be present in a half-finished computer for the machine to be able to operate on it. The specification is a set of P numbers 0, 1 or 2 (one number for each part), where 0 means that corresponding part must not be present, 1 — the part is required, 2 — presence of the part doesn't matter.

Output specification describes the result of the operation, and is a set of P numbers 0 or 1, where 0 means that the part is absent, 1 — the part is present.

The machines are connected by very fast production lines so that delivery time is negligibly small compared to production time.

After many years of operation the overall performance of the ACM Computer Factory became insufficient for satisfying the growing contest needs. That is why ACM directorate decided to upgrade the factory.

As different machines were installed in different time periods, they were often not optimally connected to the existing factory machines. It was noted that the easiest way to upgrade the factory is to rearrange production lines. ACM directorate decided to entrust you with solving this problem.


Input

Input file contains integers P N, then N descriptions of the machines. The description of ith machine is represented as by 2 P + 1 integers Qi Si,1Si,2...Si,PDi,1Di,2...Di,P, where Qi specifies performance, Si,j — input specification for part j, Di,k — output specification for part k.

Constraints

1 ≤ P ≤ 10, 1 ≤ N ≤ 50, 1 ≤ Qi ≤ 10000

Output

Output the maximum possible overall performance, then M — number of connections that must be made, then M descriptions of the connections. Each connection between machines A and B must be described by three positive numbers A B W, where W is the number of computers delivered from A to B per hour.

If several solutions exist, output any of them.

Sample Input
Sample input 1
3 4
15  0 0 0  0 1 0
10  0 0 0  0 1 1
30  0 1 2  1 1 1
3   0 2 1  1 1 1
Sample input 2
3 5
5   0 0 0  0 1 0
100 0 1 0  1 0 1
3   0 1 0  1 1 0
1   1 0 1  1 1 0
300 1 1 2  1 1 1
Sample input 3
2 2
100  0 0  1 0
200  0 1  1 1
Sample Output
Sample output 1
25 2
1 3 15
2 3 10
Sample output 2
4 5
1 3 3
3 5 3
1 2 1
2 4 1
4 5 1
Sample output 3
0 0
Hint
Bold texts appearing in the sample sections are informative and do not form part of the actual data.

题意:

造电脑,需要用尽量少的时间来制造尽量多的电脑。有n(1<=n<=50)个机器,每一台机器一次可以组装q(1<=q<=10000)台电脑,每台电脑有p(1<=p<=10)个零件,但机器只能组装部分零件。请设计一套算法来保证每经过一次生产线最多有几台电脑可以完成组装。(机器不一定要全部用上,所有部件都完成才算完成一台电脑)

机器对应的状态如下:

组装前

0:这个部件没有才能处理。

1:这个部件有才能处理。

2:有没有都无所谓了。

组装后:

0:这个部件依然缺着。

1:这个部件已组装完成。

思路:
最大流+拆点坑点:注意这个题因为是个Special Judge,所以对边的输出顺序没要求,另外注意不是单纯的输出增广路径。
例如如果输入
3 5
20 0 1 0 1 1 0
10 0 0 0 0 1 0
5  0 0 0 0 1 0
5  1 1 0 1 1 1
5  1 1 0 1 1 1

那么增广路径为2->1->4和2->1->5,两条路径的值均为5。但正确结果应该为

10 3
1 4 5
1 5 5
2 1 10

这一点做题时要根据题意自己注意。

代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>

using namespace std;

const int MAXN = 55;
const int INF = 0x3f3f3f3f;

int P,N;

struct Edge
{
	int to,value,rev;
	Edge() {}
	Edge(int a,int b,int c):to(a),value(b),rev(c) {}
};

vector<Edge> E[MAXN*2];

struct P 
{
	int in[15],out[15];
} board[MAXN*2];

int Re[MAXN][MAXN]; 

inline void Add(int from,int to,int value)
{
	E[from].push_back(Edge(to,value,E[to].size()));
	E[to].push_back(Edge(from,0,E[from].size()-1));
}

bool MyCompare(int a,int b,int P)
{
	for(int i=1 ; i<=P ; i++)
	{
		if(board[a].out[i]!=board[b].in[i] && board[b].in[i]!=2)return false;
	}
	return true;
}

int deep[MAXN*2];

bool BFS(int root,int target)
{
	memset(deep,-1,sizeof deep);
	deep[root] = 0;
	queue<int> Q;
	Q.push(root);
	while(!Q.empty())
	{
		int t = Q.front();
		Q.pop();
		for(int i=0 ; i<E[t].size() ; i++)
		{
			Edge &e = E[t][i];
			if(e.value > 0 && deep[e.to] == -1)
			{
				deep[e.to] = deep[t] + 1;
				Q.push(e.to);
			}
		}
	}
	return deep[target] != -1;
}

int iter[MAXN*2];

int Tran(int a)
{
	if( a > N+1 )return a-N;
	return a;
}

int DFS(int root,int target,int flow)
{
	if(root == target || flow == 0)return flow;

	for(int& i=iter[root] ; i<E[root].size() ; i++)
	{
		Edge& e = E[root][i];
		if(e.value > 0 && deep[e.to] == deep[root]+1)
		{
			int nowflow = DFS(e.to,target,min(flow,e.value));
			if(nowflow > 0)
			{
				Re[Tran(root)][Tran(e.to)] += nowflow;
				Re[Tran(e.to)][Tran(root)] -= nowflow;
				e.value -= nowflow;
				E[e.to][e.rev].value += nowflow;
				return nowflow;
			}
		}
	}
	return 0;
}

int Dinic(int root,int target)
{
	int sumflow = 0;
	while(BFS(root,target))
	{
		memset(iter,0,sizeof iter);
		int t;
		while((t=DFS(root,target,INF)) > 0)
		{
			sumflow += t;
		}
	}
	return sumflow;
}

int main()
{
	int value;
	int target;
	memset(board[1].out,0,sizeof board[1].out);//点1为超级源点 
	while(scanf("%d %d",&P,&N)!=EOF)
	{
		memset(Re,0,sizeof Re);
		target = (N+1)*2;
		for(int i=1 ; i<=P ; i++)board[target].in[i] = 1; 
		for(int i=2 ; i<=N+1 ; ++i)
		{
			scanf("%d",&value);
			Add(i,i+N,value);
			for(int j=1 ; j<=P ; j++)
			{
				scanf("%d",&board[i].in[j]);
			}
			for(int j=1 ; j<=P ; j++)
			{
				scanf("%d",&board[i].out[j]);
			}
		}
		for(int i=2 ; i<=N+1 ; i++)
		{
			if(MyCompare(1,i,P))Add(1,i,INF);
			if(MyCompare(i,target,P))Add(i+N,target,INF);
			for(int j=i+1 ; j<=N+1 ; j++)
			{
				if(MyCompare(i,j,P))Add(i+N,j,INF);
				if(MyCompare(j,i,P))Add(j+N,i,INF);
			}
		}
		int re1 = Dinic(1,target);
		int re2 = 0;
		for(int i=2 ; i<=N+1 ; i++)//这里先遍历一遍Re来计算re2 
		{
			for(int j=2 ; j<=N+1 ; j++)
			{
				if(i == j)continue;
				if(Re[i][j]>0)++re2;
			}
		}
		printf("%d %d
",re1,re2);
		for(int i=2 ; i<=N+1 ; i++)
		//这里又遍历了一遍Re,这样写说实话比较浪费时间,但由于点很少我就直接两遍遍历了没考虑优化。 
		{
			for(int j=2 ; j<=N+1 ; j++)
			{
				if(i == j)continue;
				if(Re[i][j]>0)printf("%d %d %d
",i-1,j-1,Re[i][j]);
			}
		}
		for(int i=1 ; i<=target ; ++i)E[i].clear();
	}

	return 0;
}










原文地址:https://www.cnblogs.com/vocaloid01/p/9514090.html