poj3436

ACM Computer Factory
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 5574   Accepted: 1913   Special Judge

Description

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,1 Si,2...Si,P Di,1 Di,2...Di,P, where Qi specifies performance, Si,j— input specification for part jDi,k — output specification for part k.

Constraints

1 ≤ P ≤ 10, 1 ≤ ≤ 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.

题意:有P个部件和n台机器,每台机器最大能接受num[i]台电脑(生产中),每台机器有输入和输出,每个部件输入用0,1,2表示,0表示不能有接受的电脑对应的部件没装好,

1表示装好,2表示无所谓。每个部件输入用0,1表示,0表示输出电脑对应的部件没装好,1表示装好,问最多能说出多少台电脑?并输出一种方案。

看着代码来解释:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 110
using namespace std;

const int inf=0x3f3f3f3f;
struct line{
    int to,next,cap;
}p[Maxn*Maxn*2];
int head[Maxn];
int q[Maxn];
int d[Maxn]; 
int cur[Maxn]; 
int tot; 
int src,t;
int n,m;
void addedge(int a,int b,int c){
    p[tot].to=b;
    p[tot].next=head[a];
    p[tot].cap=c;
    head[a]=tot++;
}
void insert(int a,int b,int c){
    addedge(a,b,c);
    addedge(b,a,0);
}
bool bfs(){
    memset(d,-1,sizeof d);
    int s=0,e=-1;
    q[++e]=src;
    d[src]=0;
    while(s<=e){
        int u=q[s++];
        for(int i=head[u];i!=-1;i=p[i].next){
            int v=p[i].to;
            if(d[v]==-1&&p[i].cap){
                d[v]=d[u]+1;
                q[++e]=v;
            }
        }
    }
    return d[t]!=-1;
}
int dfs(int u,int alpha){ 
    if(u==t) return alpha;
    int w,used=0;
    for(int i=cur[u];i!=-1&&used<alpha;i=p[i].next){ 
        int v=p[i].to;
        if(p[i].cap&&d[v]==d[u]+1){
            w=dfs(v,min(alpha-used,p[i].cap));
            used+=w;
            p[i].cap-=w;
            p[i^1].cap+=w;
            cur[u]=i;
        }
    }
    if(!used) d[u]=-1;
    return used;
}
int dinic(){ 
    int ans=0;
    src=0,t=2*m+1; 
    while(bfs()){
        for(int i=src;i<=t;i++) cur[i]=head[i]; 
        ans+=dfs(src,inf);
    }
    return ans;
}
int num[Maxn];
int input[Maxn][20],output[Maxn][20];
int vis[Maxn][Maxn];
bool check(int x,int y){
    return x==y||y==2;
}
bool ck1(int d){ //没有1
    for(int i=0;i<n;i++)
        if(input[d][i]==1) return false;
    return true;
}
bool ck2(int d){ //全1
    for(int i=0;i<n;i++)
        if(output[d][i]!=1) return false;
    return true;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=m;i++){
            scanf("%d",num+i);
            for(int j=0;j<n;j++)
                scanf("%d",&input[i][j]);
            for(int j=0;j<n;j++)
                scanf("%d",&output[i][j]);
        }
        memset(head,-1,sizeof head);
        memset(vis,0,sizeof vis);
        tot=0;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++){
                if(i==j) continue;
                bool flag=true;
                for(int k=0;k<n;k++)
                    if(!check(output[i][k],input[j][k])){
                        flag=false;
                        break;
                    }
                if(flag){
                    insert(i+m,j,num[i]);
                    vis[i+m][j]=1;
                }
            }
        for(int i=1;i<=m;i++){
            insert(i,i+m,num[i]); //拆点
            if(ck1(i)) insert(0,i,num[i]);
            if(ck2(i)) insert(i+m,2*m+1,num[i]);
        }
        printf("%d",dinic());
        int cnt=0;
        for(int i=1;i<=m;i++){
            for(int j=head[i+m];j!=-1;j=p[j].next)
                if(vis[i+m][p[j].to]&&p[j].cap<num[i]) cnt++;
        }
        printf(" %d\n",cnt);
        for(int i=1;i<=m;i++){
            for(int j=head[i+m];j!=-1;j=p[j].next)
                if(vis[i+m][p[j].to]&&p[j].cap<num[i]){
                    printf("%d %d %d\n",i,p[j].to,num[i]-p[j].cap);
                }
        }
    }
	return 0;
}

对于某台电脑的第i个部件,有两种情况:

没装好(0):那么某台机器输入状态第i位如果是1(第i个部件必须装好),这样无法接受该台电脑,而如果是0或者2,我们需要判断除第i位外的其他位。

装好(1):那么某台机器输入状态第i位如果是0(第i个部件必须不装好),这样无法接受该台电脑,而如果是1或者2,我们需要判断除第i位外的其他位。

于是代码里就写了一个check函数来检测每一位。

刚开始电脑肯定是没装部件,就是全0状态了,那么这些电脑可以输入给那些机器呢?显然根据上面结论,机器输入状态中不能有1,于是代码里写了一个ck1函数来判断。

最后生产成功的电脑肯定是所有部件都安装好了,也就是全1装了,同理机器输入状态中不能有0,于是代码里写了一个ck2函数来判断。

接下来我们考虑每台机器是否要拆点?答案是必须的,因为每台机器的输入可以来自源点或者其余机器,而这些总流量可能会超过机器最大接受数量num[i],拆点是必要保证。

连边根据上面分析就可以了。这里不细说了!

这题还要输出一种方案,如果 采用EK算法,我们直接可以从邻接矩阵里看出,但如果用了dinic,那么就必须要用一个vis数组记录原图中机器i与机器j之间的容量了,最后跑完dinic算法,我们观察那些用vis标记过的机器组合,如果容量减少了,那显然这两台机器之间是有传输的,输出即可。


你可能感兴趣的:(poj3436)