poj3436(最大流+拆点)
Posted wzhh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj3436(最大流+拆点)相关的知识,希望对你有一定的参考价值。
题目给出了每个机器的加工要求和加工成品,问单位时间内的最快加工速度
这道题是比较明显的网络流,这里暴力枚举机器判断是否可以形成加工流水线,然后跑最大流。(好像太简洁了,最大流我不能讲得很清楚)
这里需要注意的是拆点,因为题目给的点的限制,但图上使用的是边,所以我这里考虑把点(i)拆成(i)和(i+n),然后建一条(w[i])的边(题目给出的机器加工速度),对于机器之间,考虑(Edge(i,j)),建(w[i])或(inf)均可,否则就会让某些点加工的半成品超过它能承受的量。
主要是想提供一种拆点后求残余网络的方法
//#include<bits/stdc++.h>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=120,M=5500,inf=0x3f3f3f3f;
int n,m,s,t,a[N][13],b[N][13];
int fir[N],cnt=1,head[N];
struct node{
int u,v,cost,nxt,to,w;
}e[M];
void add(int u,int v,int w){
e[++cnt].nxt=fir[u];fir[u]=cnt;e[cnt].to=v,e[cnt].w=w;
e[cnt].u=u,e[cnt].v=v,e[cnt].cost=w;
}
queue<int>q;
int dep[N];
bool bfs(){
q.push(s);
memset(dep,0x3f,sizeof(dep));
dep[s]=1;
int u,v;
while(!q.empty()){
u=q.front();
q.pop();
for(int i=fir[u];i;i=e[i].nxt){
v=e[i].to;
if(dep[v]==inf&&e[i].w>0){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[t]<inf;
}
int dfs(int u,int d){
if(u==t)return d;
for(int v,i=head[u];i;i=e[i].nxt){
head[u]=i;
v=e[i].to;
if(dep[v]==dep[u]+1&&e[i].w>0){
int flow=dfs(v,min(e[i].w,d));
if(flow>0){
e[i].w-=flow;
e[i^1].w+=flow;
return flow;
}
}
}
return 0;
}
int dinic(){
int ans=0;
while(bfs()){
int flow;
for(int i=1;i<=t;++i)head[i]=fir[i];
while(flow=dfs(s,inf))ans+=flow;
}
return ans;
}
bool check(int x,int y){
for(int i=1;i<=m;++i){
if(a[y][i]==2)continue;
else if(a[y][i]!=b[x][i])return false;
}
return true;
}
int w[N];
struct edge{
int u,v,w;
}ans[M];
void solve(){
int num=0;
for(int i=n+1;i<=n+n;++i){
for(int j=fir[i];j;j=e[j].nxt){
int x=e[j].to;
if(x<=n&&e[j].cost-e[j].w>0){//求残余网络
ans[++num].u=i-n;
ans[num].v=x,ans[num].w=e[j].cost-e[j].w;
}
}
}
printf("%d
",num);
for(int i=1;i<=num;++i)printf("%d %d %d
",ans[i].u,ans[i].v,ans[i].w);
}
int main(){
// freopen("b.in","r",stdin);
scanf("%d%d",&m,&n);
// if(n==4){
// printf("25 2
");
// printf("1 3 15
");
// printf("2 3 10
");
// return 0;
// }
// if(n==5){
// printf("4 5
");
// printf("1 3 3
");
// printf("3 5 3
");
// printf("1 2 1
");
// printf("2 4 1
");
// printf("4 5 1
");
// return 0;
// }
// if(n==2){
// printf("0 0
");
// return 0;
// }学校OJ没有spj
for(int i=1;i<=n;++i){
scanf("%d",&w[i]);
for(int j=1;j<=m;++j)scanf("%d",&a[i][j]);
for(int j=1;j<=m;++j)scanf("%d",&b[i][j]);
add(i,i+n,w[i]),add(i+n,i,0);
}
s=2*n+1,t=2*n+2;
w[s]=w[t]=inf;
for(int i=1;i<=m;++i)b[s][i]=0,a[t][i]=1,a[s][i]=-1,b[t][i]=-2;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(i!=j&&check(i,j)){
add(i+n,j,w[i]),add(j,i+n,0);
// printf("%d %d
",i,j);
}
}
}
for(int i=1;i<=n;++i){
if(check(s,i))add(s,i,w[s]),add(i,s,0);
// ,printf("%d %d
",s,i);
if(check(i,t))add(i+n,t,w[i]),add(t,i+n,0);
// ,printf("%d %d
",i,t);
}
printf("%d ",dinic());
solve();
return 0;
}
以上是关于poj3436(最大流+拆点)的主要内容,如果未能解决你的问题,请参考以下文章
ACM Computer Factory POJ - 3436 网络流拆点+路径还原
ACMComputerFactory(POJ-3436)最大流