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\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;
}

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

时间: 2024-11-02 07:23:49

poj3436(最大流+拆点)的相关文章

hdu 4289 Control(网络流 最大流+拆点)(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4289 Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1545    Accepted Submission(s): 677 Problem Description You, the head of Department o

POJ3422 Kaka&#39;s Matrix Travels(最大费用最大流 + 拆点)

题目链接:http://poj.org/problem?id=3422 题意:有一个n*n的矩阵,格子中的元素是费用,KaKa从左上角开始出发要到达右下角,但是他只能向下走或者向右走,且走过的格子赋值为0,可以走K次,问K次后KaKa能获得的最大费用是多少? 思路:首先解释一下为什么要拆点?    因为要获得最大费用,所以假设当前步选择先下走,最终得到的结果可能不是最大值,但根据题意却把走过的格子赋为0了,这就影响了最终结果.所以进行拆点,把每个点拆成两个点,入度点和出度点,本点的入度点连接着本

HDU 2686 Matrix(最大费用最大流+拆点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 和POJ3422一样 删掉K把汇点与源点的容量改为2(因为有两个方向的选择)即可 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int ma

POJ 3422 Kaka&#39;s Matrix Travels(最大费用最大流 + 拆点)

题目链接:http://poj.org/problem?id=3422 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka moves one rook from the left-upper grid to the right-bottom one, taking

POJ--3422--Kaka&#39;s Matrix Travels【最小费用最大流+拆点】

链接:http://poj.org/problem?id=3422 卡卡 题意:卡卡的矩阵之旅,有一个n*n的矩阵,卡卡要从左上角走到右下角,每次他只能往右或往下走,卡卡可以走k遍这个矩阵,每个点有一个num值,卡卡走到这里可以获得num点,一个点只能获得一次num值,问卡卡走完k遍后身上num值最大可以是多少? 思路:其实看到这题时没思路,图论书上说了建图的方式,但没有说为什么,我不解,网上搜了一下解题报告,百度了两页,我看到的博客都是写了如何建图,但没有写为什么要这么建..我觉得我真是弱渣,

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

POJ 1698 Alice&#39;s Chance(最大流+拆点)

POJ 1698 Alice's Chance 题目链接 题意:拍n部电影,每部电影要在前w星期完成,并且一周只有一些天是可以拍的,每部电影有个需要的总时间,问是否能拍完电影 思路:源点向每部电影连边,容量为d,然后每部电影对应能拍的那天连边,由于每天容量限制是1,所以进行拆点,然后连向汇点即可 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> usi

POJ 1698 Alice&amp;#39;s Chance(最大流+拆点)

POJ 1698 Alice's Chance 题目链接 题意:拍n部电影.每部电影要在前w星期完毕,而且一周仅仅有一些天是能够拍的,每部电影有个须要的总时间,问能否拍完电影 思路:源点向每部电影连边,容量为d,然后每部电影相应能拍的那天连边,因为每天容量限制是1.所以进行拆点,然后连向汇点就可以 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> us

poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic

poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 15时39分22秒 * File Name: poj2391.cpp */ #include <ctime> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring&g