• 题意
    • 需要拼装电脑,每台电脑需要有p个零件,设为一个零件列表,一开始是 0 0 0 0 …
    • 现在有n个加工车间,每个车间可以加工有特定零件列表的电脑,然后产出加工后的电脑(也是一个零件列表),单位时间内能加工q台
    • 问当流水线稳定后,单位时间内能够拼装多少台完整的电脑
    • 输入格式 p n
      • q[i] in[i][j] out[i][j]  (n为第一维,p为第二维)
      • in代表能加工的电脑零件列表 0为该零件不能有 1为必须有 2为可有可无
      • out代表产出的电脑零件列表 0为该零件不能有 1为有 (产出没有可有可无这种操作)
    • 输出
      • 单位产量 用到的车间数
      • 以及用到车间之间的关系(比如 1 3 5表示1号车间向3号车间单位时间内输送了5个半成品)
  • 题解
    • 直接拆点建图
      • 将一个车间拆成加工车间(1~n)与产出车间(n+1~n*2)
      • 将每个加工车间i连向产出车间i+n,容量为q[i]
      • 设置源点s(0),将s连向加工列表为若干个0与若干个2组成的加工车间,容量无限
      • 设置汇点t(2*n+1),将产出列表全为1的加工车间连向t,容量无限
      • 遍历寻找满足车间产出列表的所有加工列表车间,从产出车间连向加工车间,容量无限
    • 还有一个问题在于如何输出每条边的流量
      • 我们建的边有些为了方便,选择了无限容量,虽然实际上可以计算得出流量,但是在意义上不明确,考虑用反向边的容量来得出流量
      • 我们知道每条建的边都有一条反向边,即表示“在寻找增广路时可反向流过的流量”,反向边上流量的大小就是实际上正向流过的流量大小
      • 我们要找的是从产出车间到加工车间之间的流量,所以我们只要从加工车间开始找边,除了连向源点的反向边以及连向同一车间拆点出来的边以外,其他的边上的容量就是车间 ver[j]-n 流入 车间i的流量,保存统计输出即可
  • 代码
    • #include<cstdio>
      #include<cstring>
      #include<algorithm>
      #include<queue>
      #include<iostream>
      using namespace std;
      #define rep(i,a,n) for(int i=a;i<=n;++i)
      #define per(i,a,n) for(int i=n;i>=a;--i)
      typedef long long ll;
      typedef unsigned long long ull;
      const int inf=1<<29,N=10010,M=300010;
      int head[N],ver[N],edge[N],Next[N],d[N];
      int n,p,s,t,tot,maxflow;
      queue<int>q;
      void add(int x,int y,int z) {
      	ver[++tot]=y;
      	edge[tot]=z;
      	Next[tot]=head[x];
      	head[x]=tot;
      	ver[++tot]=x;
      	edge[tot]=0;
      	Next[tot]=head[y];
      	head[y]=tot;
      }
      bool bfs() { //在残量网络上构造分层图
      	memset(d,0,sizeof(d));
      	while(q.size())q.pop();
      	q.push(s);
      	d[s]=1;
      	while(q.size()) {
      		int x=q.front();
      		q.pop();
      		for(int i=head[x]; i; i=Next[i])
      			if(edge[i]&&!d[ver[i]]) {
      				q.push(ver[i]);
      				d[ver[i]]=d[x]+1;
      				if(ver[i]==t)return 1;
      			}
      	}
      	return 0;
      }
      int dinic(int x,int flow) { //在当前分层图上增广
      	if(x==t)return flow;
      	int rest=flow,k;
      	for(int i=head[x]; i; i=Next[i])
      		if(edge[i]&&d[ver[i]]==d[x]+1) {
      			k=dinic(ver[i],min(rest,edge[i]));
      			if(!k)d[ver[i]]=0;
      			edge[i]-=k;
      			edge[i^1]+=k;
      			rest-=k;
      		}
      	return flow-rest;
      }
      struct ss {
      	int in[20];
      	int out[20];
      	int q;
      } machines[N];
      int ans[110][110];
      int main() {
      	while(scanf("%d%d", &p,&n)!=EOF) {
      		memset(ans,0,sizeof(ans));
      		tot=1;
      		memset(head,0,sizeof(head));
      		s=0, t=n*2+1;
      		rep(i,1,n) {
      			scanf("%d", &machines[i].q);
      			add(i,i+n,machines[i].q);
      			rep(j,1,p) {
      				scanf("%d", &machines[i].in[j]);
      			}
      			rep(j,1,p) {
      				scanf("%d", &machines[i].out[j]);
      			}
      		}
      		rep(i,1,n) {
      			int flag=1;
      			rep(j,1,p) {
      				if(machines[i].in[j]==1) {
      					flag=0;
      					break;
      				}
      			}
      			if(flag)add(s,i,inf);
      			flag=1;
      			rep(j,1,p) {
      				if(machines[i].out[j]!=1) {
      					flag=0;
      					break;
      				}
      			}
      			if(flag)add(i+n,t,inf);
      		}
      		rep(i,1,n) {
      			rep(j,1,n) {
      				if(i!=j) {
      					int flag=1;
      					rep(k,1,p) {
      						if(machines[j].in[k]!=2&&machines[j].in[k]!=machines[i].out[k]) {
      							flag=0;
      							break;
      						}
      					}
      					if(flag)add(i+n,j,inf);
      				}
      			}
      		}
      		maxflow=0;
      		int flow=0;
      		while(bfs())
      			while(flow=dinic(s,inf))maxflow+=flow;
      		int cnt=0;
      		for(int i=1;i<=n;++i){
      			for(int j=head[i];j;j=Next[j]){
      				if(ver[j]!=i+n&&ver[j]!=0&&edge[j]>0){
      					++cnt;
      					ans[ver[j]-n][i]=edge[j];
      				}
      			}
      		}
      		printf("%d %d\n", maxflow,cnt);
      		rep(i,1,n){
      			rep(j,1,n){
      				if(ans[i][j]){
      					printf("%d %d %d\n", i,j,ans[i][j]);
      				}
      			}
      		}
      	}
      	return 0;
      }
      

发表评论

邮箱地址不会被公开。 必填项已用*标注