hdu2686/hdu3376 最小费用流最大流 拆点

  虽然题目求的是最大费用,但是我们可以通过转换就变为最小费用。用一个比最大值更的数与每个数的差作为费用值。最后处理回来就i可以了。有些人用直接每个值都乘以-1,这样更简单。

  做这题,我对为什么不拆点就会错这个问题想了很久,也问了一些人。最后得出了一些知识。

  在《挑战程序设计竞赛》的214页有讲。

  点有容量限制,就必须拆点来实现。

  3
  1 1 0
  1 1 1
  0 1 1
  在这组数据中,我们按从左到右,从上到下的顺序标出点的序号。
  1 → 2    3
  ↓    ↓
  4 → 5 → 6
        ↓    ↓
  7    8 → 9
  不拆点建图,是有两条路径的。但是5这个点被经过了2次,只有一条路径。点只能经过一次没有体现出来。

  所以需要拆点。怎么拆了?像这样。

  1 → 2    3
  ↓    ↓
  4 → 5

       ↓

    10→ 6
        ↓    ↓
  7    8 → 9

  这样5 →  10的容量限制为1时,就能限制5这个点的容量为1了。

下面是hdu3376的代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 const int N =1000010, M=4000100,INF=0x3f3f3f3f;
  8 struct node
  9 {
 10     int to, next, c ,f;//c是容量,f是费用
 11 }edge[M];
 12 int head[N],dis[N],load[N],p[N];
 13 bool vis[N];
 14 int tot,flow,cost;
 15 bool spfa(int S, int E,int n)
 16 {
 17     queue<int > que;
 18     memset(vis,0,sizeof(vis));
 19     memset(load,-1,sizeof(load));
 20     memset(p,-1,sizeof(p));
 21     for(int i=0;i<=n;i++)
 22         dis[i]=INF;
 23     que.push(S);
 24     dis[S]=0;
 25     vis[S]=1;
 26     while(!que.empty())
 27     {
 28         int u=que.front();
 29         que.pop();
 30         vis[u]=0;
 31         for(int i=head[u];i!=-1;i=edge[i].next)
 32         {
 33             if(edge[i].c)
 34             {
 35                 int v=edge[i].to;
 36                 if(dis[v]-dis[u]>edge[i].f)
 37                 {
 38                     dis[v]=dis[u]+edge[i].f;
 39                     p[v]=u;
 40                     load[v]=i;
 41                     if(!vis[v])
 42                     {
 43                         vis[v]=1;
 44                         que.push(v);
 45                     }
 46                 }
 47             }
 48         }
 49     }
 50     if(dis[E]==INF) return 0;
 51     return 1;
 52 }
 53 void MCF(int S, int E,int n)
 54 {
 55     int u,mn;
 56     flow=cost=0;
 57     while(spfa(S,E,n))
 58     {
 59         u=E; mn=INF;
 60         while(p[u]!=-1)
 61         {
 62             mn=min(edge[load[u]].c, mn);
 63             u=p[u];
 64         }
 65         u=E;
 66         while(p[u]!=-1)
 67         {
 68             edge[load[u]].c-=mn;
 69             edge[load[u]^1].c+=mn;
 70             u=p[u];
 71         }
 72         cost+=dis[E]*mn;
 73         flow+=mn;
 74     }
 75 }
 76 void addedge(int a,int b,int c,int d)
 77 {
 78     edge[tot].to=b;edge[tot].c=c;edge[tot].f=d;
 79     edge[tot].next=head[a];head[a]=tot++;
 80     edge[tot].to=a;edge[tot].c=0;edge[tot].f=-d;
 81     edge[tot].next=head[b];head[b]=tot++;
 82 }
 83 void init()
 84 {
 85     tot=0;
 86     memset(head,-1,sizeof(head));
 87 }
 88 int nd[N];
 89 int main()
 90 {
 91     //freopen("test.txt","r",stdin);
 92     int n,i,j,k,a,s,e,b;
 93     while(scanf("%d",&n)!=EOF)
 94     {
 95         init();
 96         b=n*n;
 97         s=2*b+1;e=s+1; a=100;
 98         for(i=1;i<=b;i++) {scanf("%d",&nd[i]);a=max(a,nd[i]);}
 99         a++;
100         addedge(s,1,2,0);
101         addedge(2*b,e,2,0);
102         for(i=1;i<=b;i++)
103         {
104             if(i==1) addedge(i,i+b,2,a-nd[i]);
105             else if(i==b) addedge(i,i+b,2,a-nd[i]);
106             else addedge(i,i+b,1,a-nd[i]);
107             if(i%n) addedge(i+b,i+1,1,0);//向右
108             if(i<=b-n) addedge(i+b,i+n,1,0);//向下
109         }
110         MCF(s,e,e);
111         cost-=a-nd[1]+a-nd[b];
112         int ans=4*a*(n-1)-cost;
113         printf("%d\n",ans);
114     }
115     return 0;
116 }

时间: 2024-10-06 12:34:35

hdu2686/hdu3376 最小费用流最大流 拆点的相关文章

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