POJ3436 ACM Computer Factory (最大流-EK)

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 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.

 

题意:

给定两个整数P,N

解下来N行,每行一个整数Qi,代表第i台机器的性能(产出电脑的数量),随后P个数字代表生产第i台机器所需要的零部件(0代表不需要,1代表需要,2代表可以需要可以不需要),随后P个数字代表第i台机器能够产出的部件(0代表不能产出,1代表能产出)。

输出结果如下:

输出两个数x,y(x代表所有机器能够产出的最大电脑数量,y代表电脑间的连接信息(这一部分接下来会提到))

题解:

关键是将每台机器拆成两个点,从同一台机器到同一台机器之间连线的权值即为这个机器能够生产的最大的电脑的数量。

for example sample 1:
                                              

找源点和汇点,将类似于0 0 0、0 0 2 这样的数据跟源点连接(因为2可有可无,0是必须没有),将1 1 1....(全为1,可以想象成都准备好了,直接生产)与汇点连接。

                                                                 

将各个机器之间建立连接关系,对于第i台机器,如果其输出部件信息为0 0 2,那么其可以与除第i台机器外的其他的机器的输入部件为0 0 1或者0 0 0或者0 0 2进行连接,发现规律为只要存在比如0 0 1和0 0 0这样的1+0=1(也就是出现1的情况的)就不成立,其它的都成立。

                                            

最后跑最大流即可。

 

代码如下:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<cstring>
#include<set>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
#define mem(a,b) memset((a),(b),sizeof(a))
#define fr(x,n) for(int i=x;i<=n;++i)
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll,ll>;
const double pi=acos(-1.0);
const double eps=1e-9;
const int mod=1e9+7;
const int maxn=5e2+100;
const int inf=0x3f3f3f3f;

int p,n;
int number1[maxn][maxn],number2[maxn][maxn];
int w[maxn];
int G[maxn][maxn];
int GG[maxn][maxn];
int pre[maxn],flow[maxn];

struct Edge
{
    int u,v,w;
} edge[maxn];

int bfs(int s,int t)
{
    queue<int>q;
    memset(pre,-1,sizeof(pre));
    memset(flow,0,sizeof(flow));
    pre[s]=0,flow[s]=inf;
    q.push(s);
    while(!q.empty())
    {
//        int fr=q.top();
        int fr=q.front();
        if(fr==t) break;
        q.pop();
        for(int i=1; i<=t; ++i)
        {
            if(G[fr][i]>0&&pre[i]==-1&&i!=s)
            {
                pre[i]=fr;
                flow[i]=min(flow[fr],G[fr][i]);
                q.push(i);
            }
        }
    }
    if(pre[t]==-1)
        return -1;
    return flow[t];
}

int EK(int s,int t)
{
    int tol=0,data;
    while(1)
    {
        data=bfs(s,t);
        if(data==-1)
            break;
        int tt=t;
        while(tt!=s)
        {
            G[pre[tt]][tt]-=data;
            G[tt][pre[tt]]+=data;
            tt=pre[tt];
        }
        tol+=data;
    }
    return tol;
}

int main()
{
    while(~scanf("%d%d",&p,&n))
    {
        for(int i=1; i<=n; ++i)
        {
            scanf("%d",&w[i]);
            for(int j=1; j<=p; ++j)
            {
                scanf("%d",&number1[i][j]);
            }
            for( int j=1; j<=p; ++j)
            {
                scanf("%d",&number2[i][j]);
            }
        }
        memset(G,0,sizeof(G));
        for(int i=1; i<=n; ++i)
        {
            int ans=0;
            for(int j=1; j<=p; ++j)
            {
                if(number1[i][j]==1)
                {
                    ++ans;
                }
            }
            //源点相连
            if(ans==0)
            {
                G[0][i]=inf;
            }
            ans=0;
            for(int j=1; j<=p; ++j)
            {
                ans+=number2[i][j];
            }
            if(ans==p)
            {
                G[n+i][2*n+1]=inf;
            }
            else
            {
                for(int j=1; j<=n; ++j)
                {
                    if(i==j) continue;
                    bool flag=true;
                    for(int k=1; k<=p; ++k)
                    {
                        if(number2[i][k]+number1[j][k]==1)
                        {
                            flag=false;
                            break;
                        }
                    }
                    if(flag)
                    {
                        G[n+i][j]=inf;
                    }
                }

            }
        }
        for(int i=1; i<=n; ++i)
        {
            G[i][n+i]=w[i];
        }
        for(int i=1; i<=2*n+1; ++i)
        {
            for(int j=1; j<=2*n+1; ++j)
            {
                GG[i][j]=G[i][j];
            }
        }
        int putss=EK(0,2*n+1);
        int tot=0;
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=n; ++j)
            {
                if(GG[i+n][j]-G[i+n][j]>0)
                {
                    edge[++tot].u=i;
                    edge[tot].v=j;
                    edge[tot].w=GG[i+n][j]-G[i+n][j];
                }
            }
        }
        printf("%d %d\n",putss,tot);
        for(int i=1; i<=tot; ++i)
        {
            printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
        }


    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值