传送门:https://vjudge.net/problem/POJ-3436
题目大意:
每台电脑由p个零件组成,编号1~n。生产电脑完全由N台全自动的机器完成。每台机器能够添加一些零件和移除一些电脑零件。
用生产效率、输入规格、输出规格来描述每一台机器。
输入规格描述电脑必须具有那些零件,机器才能去加工它。这个输入规格由p个0,1,2整数的集合,0意味该零件必须不能存在,机器才能加工这个这台半成品电脑。相应的1是该零件必须存在,2是存在与否没有影响。
输出规格描述该半成品电脑经过该机器存在那些零件。这个输出规格是由0,1整数构成的集合,0意味着该办成品电脑,不具有该零件,1表示该电脑具有该零件。
问该工厂最大的生产效率是多少。
解题思路:
首先根据信息建图:
其中某个零件的组合方式有 00 01 02 10 11 12:
可以看出若组合中有01 10说明该机器不能连在一起。
耶耶耶,终于做对了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; const int MAXN=150; const int INF=1<<20; struct Machine{ int flow; int in[15],out[15]; }mac[MAXN]; //检查该机器和源点之间是否有边 bool checkS(Machine a,int P){ for(int i=0;i<P;i++) if(a.in[i]==1) return false; return true; } //检查该机器和汇点n+1之间是否有边 bool checkT(Machine a,int P){ for(int i=0;i<P;i++) if(a.out[i]!=1) return false; return true; } //检查两个机器之间是否有边 bool checkEdge(Machine a,Machine b,int P){ for(int i=0;i<P;i++) if(a.out[i]+b.in[i]==1) return false; return true; } struct Edge{ int to,next; int init; int flow; }edges[MAXN*10]; int head[MAXN]; int tot; void init(){ tot=0; memset(head,-1,sizeof(head)); } void addEdge(int u,int v,int flow){ edges[tot].to=v; edges[tot].flow=flow; edges[tot].init=flow; edges[tot].next=head[u]; head[u]=tot++; } int level[MAXN]; bool makelevel(int s,int t ){ memset(level,0,sizeof(level)); level[s]=1; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); if(u==t) return true; for(int i=head[u];i!=-1;i=edges[i].next){ int v=edges[i].to; if(!level[v]&&edges[i].flow){ level[v]=level[u]+1; q.push(v); } } } return false; } int DFS(int now,int maxf,int t){ if(now==t) return maxf; int ret=0,f; for(int k=head[now];k!=-1;k=edges[k].next){ int v=edges[k].to; if(edges[k].flow&&level[v]==level[now]+1){ f=DFS(v,min(maxf-ret,edges[k].flow),t); edges[k].flow-=f; edges[k^1].flow+=f; ret+=f; } if(ret==maxf) return ret; } return ret; } int Dinic(int s,int t){ int ans=0; while(makelevel(s,t)) ans+=DFS(s,INF,t); return ans; } struct Node{ int u; int v; int cap; Node(int u,int v,int cap):u(u),v(v),cap(cap){}; Node(){}; }; int main(){ int P,N; while(scanf("%d%d",&P,&N)!=EOF){ for(int i=1;i<=N;i++){ scanf("%d",&mac[i].flow); for(int j=0;j<P;j++) scanf("%d",&mac[i].in[j]); for(int j=0;j<P;j++) scanf("%d",&mac[i].out[j]); } //下面是建图 init(); for(int i=1;i<=N;i++){ if(checkS(mac[i],P)){ //这是检查该机器和源点0是否有边 addEdge(0,i,mac[i].flow); addEdge(i,0,0); } if(checkT(mac[i],P)){ //这是检查该机器和汇点N+1是否有边 addEdge(i,N+1,mac[i].flow); addEdge(N+1,i,0); } for(int j=1;j<=N;j++){ //这是检查机器i和机器j是否右边 if(i==j) continue; if(checkEdge(mac[i],mac[j],P)){ addEdge(i,j,mac[i].flow); addEdge(j,i,0); } } } int res=Dinic(0,N+1); vector<Node>ans; ans.clear(); //如果最后残留网络的容量小于初始容量,说明该边是最大流走过的边 for(int u=1;u<=N;u++){ for(int j=head[u];j!=-1;j=edges[j].next){ int v=edges[j].to; if(v>0&&v<=N&&edges[j].flow<edges[j].init){ ans.push_back(Node(u,v,edges[j].init-edges[j].flow)); } } } printf("%d %d ",res,ans.size()); for(int i=0;i<ans.size();i++){ printf("%d %d %d ",ans[i].u,ans[i].v,ans[i].cap); } } return 0; }