hdu5520 最小费用最大流

来源:互联网 发布:淘宝街拍照片如何调色 编辑:程序博客网 时间:2024/05/20 10:54

hdu5520
Number Link

Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 168 Accepted Submission(s): 64

Problem Description
Number Link is a famous game available in platforms including iOS and Android. Given a board with n rows and m columns, the target of the game is to connect pairs of grids with the same numbers. Once two numbers are paired, the path connecting them will occupy the corresponding grids. The path can only go vertically or horizontally. Note that, no two paths could intersect (by sharing the same grid) in any grid. In this problem, you are going to play a modified version, called Number Link ++. See the picture below for an example.
这里写图片描述
In this new game, you can use two types of paths. Type I is to connect two number grids with different parities (i.e., connect odd number with any other even number). It might be hard to cover the entire grid with only type I path, so we allow type II path, which is a circle path covers only the empty grids (the only special case of type II path is a path only connecting two adjacent empty grids; see the figure above). Since there is no free lunch, we have no free path either. When goes from grid (a,b) to an adjacent grid (c,d), you have to pay for a certain amount of tolls. The cost is the same when goes back from (c,d) to (a,b). Usually the cost of a path is the sum of tolls you paid by traveling along the grids on this path. The only exception is for the special case of type II path. In that case, you have to pay twice the cost (since it is a circle).
The total cost of the game is the sum of costs for all the paths. Can you help me figure out the paths so that each grid is on exactly one path? If there exists such solution, what is the minimum possible cost?

Input
The first line of input consists of an integer T, which is the number of test cases.
Each case begins with two integers, n and m, in a line (1≤n,m≤50).
The next n lines describe the board. Each line consists of m nonnegative numbers, which describe the status of each column from left to right. If the number is zero, then the grid is empty; otherwise it indicates the number on the corresponding grid.
The next n−1 lines each have m nonnegative numbers, which describe the cost of vertical connection. The j-th number in i-th line is the cost when travels from grid (i,j) to (i+1,j).
The next n lines each have m−1 nonnegative numbers, which describe the cost of horizontal connection. The j-th number in i-th line is the cost for a path to go from grid (i,j) to (i,j+1).
All the numbers, including the answer, can be represented using 32-bit signed integer.

Output
For each test case, first output the case number, then output a single number, which is the minimum cost possible to finish the game. When there is no solution available, simply output -1.

Sample Input
3
3 3
1 0 0
1 0 0
2 0 2
1 2 1
2 1 1
3 1
5 6
1 4
1 4
1 1 2 2
1 2 3
3 5
0 0 0 0 0
0 5 0 6 0
0 0 0 0 0
1 1000 1000 1000 1
1 1000 1000 1000 1
1 1 1 1
1000 1 1 1000
1 1 1 1

Sample Output
Case #1: 10
Case #2: -1
Case #3: 14
Hint

Below are the solutions corresponding to case 1 and case 3 respectively. In case 1, you should double pay the red path, since it is a special case of type II path.
这里写图片描述
这里写图片描述
题意:给了一个格子,每个格子里放了一个数,要把奇数与偶数用线连起来,剩余的0的话,要连成一个环,两个相邻连接也算作环,每个相邻格子之间的“墙”是有花费的,而且要求每个格子只能被一条线占用,问将所有格子连接起来,最少花费是多少。
显然是网络流费用流问题,问题是怎么建图,仔细研究研究就看出来,将每个格子分成两个点,建立源点S,终点T,
(1)S与每个奇数入点相连,流量为1,花费为0,
(2)每个偶数点出点与T相连,流量为1,话费为0;
(3)相邻的格子,X ,Y,将X分解成入点A,出点B,将Y分解成入点C,出点D,B->C ,[1,cost] , D->A[1,cost]
然后由起点向终点跑一个最小费用最大流,满流的话可以使所有格子连接起来,不满流输出-1.
画了一个小时的图
画了一个小时的图

#include <iostream>#include <stdio.h>#include <algorithm>#include <math.h>#include <queue>#include <set>#include <string.h>#include <vector>using namespace std;const int MAXN=5050;const int MAXM=1e6+6;const int INF=0x3f3f3f3f;struct node{    int to,next,cap,flow,cost;} edge[MAXM];int head[MAXN],tot;void add_edge(int u,int v,int cap,int cost){    edge[tot].cap=cap;    edge[tot].flow=0;    edge[tot].cost=cost;    edge[tot].next=head[u];    edge[tot].to=v;    head[u]=tot++;    edge[tot].to=u;    edge[tot].cap=0;    edge[tot].flow=0;    edge[tot].cost=-cost;    edge[tot].next=head[v];    head[v]=tot++;}void init(){    memset(head,-1,sizeof(head));    tot=0;}int n,m,v;int s,t;int cal_num(int i,int j){    return (i-1)*m+j;}int dis[MAXN],pre[MAXN];bool vis[MAXN];bool spfa(){    queue<int>que;    for(int i=0; i<=n*m*2+5; i++)    {        dis[i]=INF;        vis[i]=false;        pre[i]=-1;    }    dis[s]=0;    vis[s]=true;    que.push(s);    while(!que.empty())    {        int u=que.front();        que.pop();        vis[u]=false;        for(int i=head[u]; i!=-1; i=edge[i].next)        {            v=edge[i].to;            if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost)            {                dis[v]=dis[u]+edge[i].cost;                pre[v]=i;                if(!vis[v])                {                    vis[v]=true;                    que.push(v);                }            }        }    }    if(pre[t]==-1)        return false;    return true;}int max_flow_min_cost(int allcap){    int flow=0,cost=0;    while(spfa())    {        int Min=INF;        for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to])        {            if(Min>edge[i].cap-edge[i].flow)                Min=edge[i].cap-edge[i].flow;        }        for(int i=pre[t]; i!=-1; i=pre[edge[i^1].to])        {            edge[i].flow+=Min;            edge[i^1].flow-=Min;            cost+=edge[i].cost*Min;        }        flow+=Min;    }    if(flow==allcap)        return cost;    else        return -1;}int getint(){    bool s=0;    int a,f;    while(a=getchar(),!(a>='0'&&a<='9')&&a!='-');    if(a-'-')        a-='0';    else        a=0,s=1;    while(f=getchar(),f>='0'&&f<='9')        a=a*10+f-'0';    return s ? -a:a;}int main(){    int T;    int x,temp;    int allcap;    T=getint();    for(int cas=1; cas<=T; cas++)    {        n=getint();        m=getint();        temp=n*m;        s=n*m*2+1;        t=s+1;        init();        allcap=0;        for(int i=1; i<=n; i++)        {            for(int j=1; j<=m; j++)            {                x=getint();                if(x==0)                {                    add_edge(s,cal_num(i,j),1,0);                    allcap++;                    add_edge(cal_num(i,j)+temp,t,1,0);                }                else                {                    if(x&1)                    {                        add_edge(s,cal_num(i,j),1,0);                        allcap++;                    }                    else                        add_edge(cal_num(i,j)+temp,t,1,0);                }            }        }        for(int i=1; i<=n-1; i++)        {            for(int j=1; j<=m; j++)            {                x=getint();                add_edge(cal_num(i,j),cal_num(i+1,j)+temp,1,x);                add_edge(cal_num(i+1,j),cal_num(i,j)+temp,1,x);            }        }        for(int i=1; i<=n; i++)        {            for(int j=1; j<=m-1; j++)            {                x=getint();                add_edge(cal_num(i,j),cal_num(i,j+1)+temp,1,x);                add_edge(cal_num(i,j+1),cal_num(i,j)+temp,1,x);            }        }        printf("Case #%d: %d\n",cas,max_flow_min_cost(allcap));    }    return 0;}/**下面这组数据肯定过不了,结果是5,0 0 之间只走了一次2 20 01 21132*/
原创粉丝点击