POJ 3436-ACM Computer Factory(最大流輸出路徑-Edmond-Karp演算法)

kewlgrl發表於2017-02-13
ACM Computer Factory
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7445   Accepted: 2664   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,1Di,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.

Source

Northeastern Europe 2005, Far-Eastern Subregion

題目意思:

每臺ACM計算機由P個部分組成,有N個機器用於組裝ACM計算機,將其中若干臺機器連在一起有可能能夠組裝成一臺完整的ACM計算機。。
給出每個機器的容納組裝的ACM計算機的最大數量Q,輸入和輸出機器的P個部分,P個部分分別用0/1/2來表示,0表示這部分不能存在,1表示這部分是必需的,2表示這部分無關緊要(存不存在都可以)。
求最大的ACM計算機數量連在一起使用的機器數、機器間傳遞的ACM計算機數目。


解題思路:

折騰了一下午…建圖就超級麻煩…參考了Discuss中大神的思路:

拆點,將一個機器拆分成兩個點,即輸入和輸出兩部分,流量是其容納的最大數量Q;
(此時結點數N應該變成2*N)
②加一個超級源點和一個超級匯點
對於機器輸入的P個部分,如果有的部分必須存在,即含1,那麼將其與超級源點相連,看作超級源點向其傳遞數量INF;
對於機器輸出的P個部分,如果有的部分必不存在,即含0,那麼將其與超級匯點相連,看作其超級匯點傳出數量INF;
(此時結點數2*N應該變成2*N+2,但是下標是從0~2*N+1
③機器間的互相傳遞是從A機器的輸出傳到B機器的輸入
因為只有0和1是完全對立的,所以相應部分分別是0和1時兩個機器之間必然不能傳遞,其他情況(0和0、1和1、2和2、0和2、1和2)均可,傳遞數量為INF。

單向圖建立完畢後,我用了Edmond-Karp演算法求解最大流,別的最大流演算法也是可以的。
然後需要求解網路中的流向,在求最大流之前複製一下建圖的陣列,使用這兩個陣列比較機器A到B之間的流量,如果流量有減少說明需要使用該機器。因為題目是Special Judge,所以不用考慮順序,可以使用STL的vector儲存後輸出即可。

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 1010
struct Node
{
    int in[11];
    int out[11];
    int q;
} s[MAXN];
struct node
{
    int from,to,cap;
    node(int a,int b,int c):from(a),to(b),cap(c) {}
};
vector<node> res;//記錄網路流中機器之間的流量
int temp[MAXN][MAXN];
int capacity[MAXN][MAXN]; //記錄殘留網路的容量
int flow[MAXN];           //標記從源點到當前節點實際還剩多少流量可用
int pre[MAXN];            //標記在這條路徑上當前節點的前驅,同時標記該節點是否在佇列中
int n,p;                  //總結點數、組成部分數
queue<int> myqueue;
int BFS(int src,int des)
{
    int i;
    while(!myqueue.empty())       //佇列清空
        myqueue.pop();
    for(i=0; i<=n+1; ++i)
        pre[i]=-1;
    pre[src]=0;
    flow[src]= INF;
    myqueue.push(src);
    while(!myqueue.empty())
    {
        int index = myqueue.front();
        myqueue.pop();
        if(index == des)            //找到了增廣路徑
            break;
        for(i=0; i<=n+1; ++i)
        {
            if(i!=src && capacity[index][i]&& pre[i]==-1)
            {
                pre[i] = index; //記錄前驅
                flow[i] = min(capacity[index][i],flow[index]);   //關鍵:迭代的找到增量
                myqueue.push(i);
            }
        }
    }
    if(pre[des]==-1)      //殘留圖中不再存在增廣路徑
        return -1;
    else
        return flow[des];
}
int maxFlow(int src,int des)
{
    int increasement= 0;
    int sumflow = 0;
    while((increasement=BFS(src,des))!=-1)
    {
        int k = des;          //利用前驅尋找路徑
        while(k!=src)
        {
            int last = pre[k];
            capacity[last][k] -= increasement; //改變正向邊的容量
            capacity[k][last] += increasement; //改變反向邊的容量
            k = last;
        }
        sumflow += increasement;
    }
    return sumflow;
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("F:/cb/read.txt","r",stdin);
    //freopen("F:/cb/out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i,j;
    while(cin>>p>>n)
    {
        int t=n;
        n*=2;
        memset(capacity,0,sizeof(capacity));
        memset(flow,0,sizeof(flow));
        for(i=1; i<=t; ++i)
        {
            cin>>s[i].q;
            capacity[i][i+t]=s[i].q;//
            bool b0=true,b1=true;
            for(j=0; j<p; ++j)
            {
                cin>>s[i].in[j];
                if(s[i].in[j]==1) b0=false;//存在1
            }
            for(j=0; j<p; ++j)
            {
                cin>>s[i].out[j];
                if(!s[i].out[j]) b1=false;//存在0
            }
            if(b0) capacity[0][i]=INF;//超級源點0
            if(b1) capacity[i+t][n+1]=INF;//超級匯點n+1
        }
        bool flag=true;
        for(i=1; i<=t; ++i)
            for(j=1; j<=t; ++j)
                if(i!=j)
                {
                    flag=true;
                    for(int k=0; k<p; ++k)
                        if(s[i].out[k]+s[j].in[k]==1)
                        {
                            flag=false;
                            break;
                        }
                    if(flag)
                        capacity[i+t][j]=INF;//機器之間
                }
        memcpy(temp,capacity,sizeof(temp));//複製capacity陣列到temp
        cout<<maxFlow(0,n+1)<<" ";
        for(int i=1; i<=t; i++)
        {
            for(int j=1; j<=t; j++)
            {
                if(i!=j)
                    if(capacity[t+i][j]<temp[t+i][j])//流量有減少說明需要使用該機器
                        res.push_back(node(i,j,temp[t+i][j]-capacity[t+i][j]));
            }
        }
        cout<<res.size()<<endl;
        for(int i=0; i<res.size(); i++)
            cout<<res[i].from<<" "<<res[i].to<<" "<<res[i].cap<<endl;
        res.clear();
    }
    return 0;
}
/*
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
*/


相關文章