码迷,mamicode.com
首页 > 其他好文 > 详细

poj3436(最大流+拆点)

时间:2019-12-01 22:50:39      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:return   inline   main   ring   注意   lin   单位   freopen   +=   

题目给出了每个机器的加工要求和加工成品,问单位时间内的最快加工速度

这道题是比较明显的网络流,这里暴力枚举机器判断是否可以形成加工流水线,然后跑最大流。(好像太简洁了,最大流我不能讲得很清楚)
这里需要注意的是拆点,因为题目给的点的限制,但图上使用的是边,所以我这里考虑把点\(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\n",num);
    for(int i=1;i<=num;++i)printf("%d %d %d\n",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\n");
//      printf("1 3 15\n");
//      printf("2 3 10\n");
//      return 0;
//  }
//  if(n==5){
//      printf("4 5\n");
//      printf("1 3 3\n");
//      printf("3 5 3\n");
//      printf("1 2 1\n");
//      printf("2 4 1\n");
//      printf("4 5 1\n");
//      return 0;
//  }
//  if(n==2){
//      printf("0 0\n");
//      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\n",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\n",s,i);
        if(check(i,t))add(i+n,t,w[i]),add(t,i+n,0);
//      ,printf("%d %d\n",i,t);
    }
    printf("%d ",dinic());
    solve();
    return 0;
}

poj3436(最大流+拆点)

标签:return   inline   main   ring   注意   lin   单位   freopen   +=   

原文地址:https://www.cnblogs.com/wzhh/p/11968055.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!