POJ3436.ACM Computer Factory(ACM计算机工厂)——最大流+拆点

http://poj.org/problem?id=3436

题目难懂!!!

题目描述:
正如你所知道的,ACM 竞赛中所有竞赛队伍使用的计算机必须是相同的,以保证参赛者在公平的环境下竞争。这就是所有这些计算机都是同一个厂家生产的原因。
每台ACM 计算机包含P 个部件,当所有这些部件都准备齐全后,计算机就可以组装了,组装好以后就可以交给竞赛队伍使用了。计算机的生产过程是全自动的,通过N 台不同的机器来完成。每台机器从一台半成品计算机中去掉一些部件,并加入一些新的部件(去除一些部件在有的时候是必须的,因为计算机的部件不能以任意的顺序组装)。每台机器用它的性(每小时组装多少台计算机)、输入/输出规格来描述。
输入规格描述了机器在组装计算机时哪些部件必须准备好了。输入规格是由P 个整数组成,
每个整数代表一个部件,这些整数取值为0, 1 或2,其中0 表示该部件不应该已经准备好了,1表示该部件必须已经准备好了,2 表示该部件是否已经准备好了无关紧要。
输出规格描述了该机器组装的结果。输出规格也是由P 个整数组成,每个整数取值为0 或1,其中0 代表该部件没有生产好,1 代表该部件生产好了。
机器之间用传输速度非常快的流水线连接,部件在机器之间传送所需的时间与机器生产时间
相比是十分小的。
经过多年的运转后,ACM 计算机工厂的整体性能已经远远不能满足日益增长的竞赛需求。因此ACM 董事会决定升级工厂。升级工厂最好的方法是重新调整流水线。ACM 董事会决定让你来解决这个问题。

将点i分为i和i+n
1.如果某台机器的输入规格没有1,就跟source连边,容量为INF;
2.如果某台机器的输出规格没有0,就跟sink连边,容量为INF;
3.如果某台机器i的输出规格符合另一台机器j的输入规格,则i+n跟j连边,容量为INF

求最流,然后输出机器之间流量增加的边

//Memory: 160K      Time: 16MS
//Language: C++     Result: Accepted
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
const int MAXN= 110;//最大顶点数
const int MAXM = 11000;//最大边数
const int INF=0x3f3f3f3f;
using namespace std;
vector<pair<int,pair<int,int> > >pi;
int n,s,t,N;
struct Edge{
    int to,next,cap,flow;
}edges[MAXM];
int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c){
    edges[tot].to=v;
    edges[tot].cap=c;
    edges[tot].flow=0;
    edges[tot].next=head[u];
    head[u]=tot++;
    edges[tot].to=u;
    edges[tot].cap=0;
    edges[tot].flow=0;
    edges[tot].next=head[v];
    head[v]=tot++;
}
void bfs(){
    memset(d,-1,sizeof(d));
    memset(gap,0,sizeof(gap));
    gap[0]=1;
    int front=0,rear=0;
    d[t]=0;
    que[rear++]=t;
    while(front!=rear){
        int u=que[front++];
        for(int i=head[u];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if(d[v]!=-1) continue;
            que[rear++]=v;
            d[v]=d[u]+1;
            gap[d[v]]++;
        }
    }
}
int isap(){
    bfs();
    memcpy(cur,head,sizeof(head));
    int top=0,x=s,flow=0;
    while(d[s]<N){
        if(x==t){
            int Min=INF,inser;
            for(int i=0;i<top;++i){
                if(Min>edges[p[i]].cap-edges[p[i]].flow){
                    Min=edges[p[i]].cap-edges[p[i]].flow;
                    inser=i;
                }
            }
            for(int i=0;i<top;++i){
                edges[p[i]].flow+=Min;
                edges[p[i]^1].flow-=Min;
            }
            flow+=Min;
            top=inser;
            x=edges[p[top]^1].to;
            continue;
        }
        int ok=0;
        for(int i=cur[x];i!=-1;i=edges[i].next){
            int v=edges[i].to;
            if(edges[i].cap>edges[i].flow&&d[v]+1==d[x]){
                ok=1;
                cur[x]=i;
                p[top++]=i;
                x=edges[i].to;
                break;
            }
        }
        if(!ok){
            int Min=N;
            for(int i=head[x];i!=-1;i=edges[i].next){
                if(edges[i].cap>edges[i].flow&&d[edges[i].to]<Min){
                    Min=d[edges[i].to];
                    cur[x]=i;
                }
            }
            if(--gap[d[x]]==0) break;
            gap[d[x]=Min+1]++;
            if(x!=s) x=edges[p[--top]^1].to;
        }
    }
    return flow;
}
int P;
struct Node{
    int p[15];
    int Q;
}node[MAXN];
bool check_edge(int i,int j){
    for(int k=0;k<P;++k){
        if(node[j].p[k]+node[i].p[k]==1) return false;
    }
    return true;
}
bool check_s(int i){
    for(int k=0;k<P;++k){
        if(node[i].p[k]==1) return false;
    }
    return true;
}
bool check_t(int i){
    for(int k=0;k<P;++k){
        if(node[i].p[k]==0) return false;
    }
    return true;
}
void Build_graph(){
    s=0,t=(n<<1)+1;
    N=t+1;
    for(int i=1;i<=n;++i){
        if(check_s(i)) addedge(s,i,INF);
        addedge(i,i+n,node[i].Q);
        if(check_t(i+n)) addedge(i+n,t,INF);
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            if(j==i) continue;
            if(check_edge(i+n,j)) addedge(i+n,j,INF);
        }
    }
}
void solve(){
    Build_graph();
    printf("%d",isap());
    int cnt=0;
    pi.clear();
    for(int u=n+1;u<=(n<<1);++u){
        for(int i=head[u];i!=-1;i=edges[i].next){
            Edge&e =edges[i];
            int v=e.to;
            if(v!=u-n&&v!=t&&e.flow>0){
                cnt++;
                pi.push_back(make_pair(u-n,make_pair(v,e.flow)));
            }
        }
    }
    printf(" %d\n",cnt);
    for(int i=0;i<cnt;++i){
        printf("%d %d %d\n",pi[i].first,pi[i].second.first,pi[i].second.second);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.cpp","r",stdin);
#endif // ONLINE_JUDGE
    while(scanf("%d%d",&P,&n)!=EOF){
        init();
        for(int i=1;i<=n;++i){
            scanf("%d",&node[i].Q);
            for(int j=0;j<P;++j){
                scanf("%d",&node[i].p[j]);
            }
            for(int j=0;j<P;++j){
                scanf("%d",&node[i+n].p[j]);
            }
        }
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值