1. 程式人生 > >ACM Computer Factory(網路流)

ACM Computer Factory(網路流)

反思:注意拆點,否則的話節點就沒用了,還有注意源點和匯點的賦值。

AC程式碼:

#include<iostream>
#include<string>
#include<cstring>
#include<iomanip>
#include<stack>
#include<queue>
#include<stdio.h>
#include<algorithm>
using namespace std;
# define inf 0x3f3f3f3f
# define maxn 100+10
# define ll long long
int p,n;
int ori[maxn][maxn],nex[maxn][maxn];
int pre[maxn],vis[maxn];
int u[maxn],v[maxn],w[maxn];
struct node
{
    int cost;
    int in[maxn];
    int out[maxn];
} a[maxn];
void init()
{
    memset(ori,0,sizeof(ori));
    memset(nex,0,sizeof(nex));
    a[1].cost=inf;
    for(int i=1; i<=p; i++)
    {
        a[1].in[i]=0;
        a[1].out[i]=0;
        a[n+2].in[i]=1;
        a[n+2].out[i]=1;
    }
    a[n+2].cost=inf;
}
bool judge(int t1,int t2)
{
    for(int i=1; i<=p; i++)
    {
        if(a[t1].out[i]!=a[t2].in[i]&&a[t2].in[i]!=2)return false;
    }
    return true;
}
bool bfs(int st,int ed)
{
    queue<int>q;
    memset(vis,0,sizeof(vis));
    vis[st]=1;
    q.push(st);
    pre[st]=st;
    while(!q.empty())
    {
        int top=q.front();
        q.pop();
        for(int i=1; i<=2*n; i++)
        {
            if(vis[i]==0&&nex[top][i])
            {
                vis[i]=1;
                pre[i]=top;
                if(i==ed)return true;
                q.push(i);
            }
        }
    }
    return false;
}
int EK(int st,int ed)
{
    int ans=0;
    while(bfs(st,ed))
    {
        int minn=inf ;
        for(int i=ed; i!=st; i=pre[i])
        {
            minn=min(minn,nex[pre[i]][i]);
        }
        for(int i=ed; i!=st; i=pre[i])
        {
            nex[pre[i]][i]-=minn;
            nex[i][pre[i]]+=minn;
        }
        ans+=minn;
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d",&p,&n))
    {
        init();
        for(int i=2; i<=n+1; i++)//從2開始是為了把1當做源點
        {
            scanf("%d",&a[i].cost);
            for(int j=1; j<=p; j++)
            {
                scanf("%d",&a[i].in[j]);
            }
            for(int j=1; j<=p; j++)
            {
                scanf("%d",&a[i].out[j]);
            }
        }
        n+=2;//和原來相比加入了源點和匯點
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(i==j)
                {
                    ori[i][j+n]=nex[i][j+n]=a[i].cost;
                }
                else if(i!=j&&judge(i,j))
                {
                    ori[i+n][j]=nex[i+n][j]=a[i].cost;
                }
            }
        }
        int ans=EK(1,n*2);
        int num=0;
        for(int i=2; i<n; i++)
        {
            for(int j=2; j<n; j++)
            {
                if(ori[i+n][j]>nex[i+n][j])//如果拆點後當前流的流量變小了,說明這條路上有流量。
                {
                    u[++num]=i;
                    v[num]=j;
                    w[num]=ori[i+n][j]-nex[i+n][j];
                }
            }
        }
        printf("%d %d\n",ans,num);
        for(int i=1; i<=num; i++)
        {
            printf("%d %d %d\n",u[i]-1,v[i]-1,w[i]);
        }
    }
    return 0;
}