HDU 5520 Number Link(费用流)

题意:给你一个n*m的网格,部分网格有数字,要求奇数的数字要和偶数的数字连在一起,空白的数字要成环,给你每个格子连接上下左右的费用,求满足条件最小费用

思路:考虑费用流,讲每个点拆点,源点S连向所有奇数点的入点,T连向所有偶数的出点,然后S连所有空白的入点,出点连T,上下左右的入点连向各自的出点,这样跑一次最小费用最大流即可


#include<bits/stdc++.h>
using namespace std;
const int maxn = 5005;
#define INF 1e9
int tot;
struct Edge
{
	int from,to,cap,flow,cost;
	Edge(){};
	Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){}
};
struct MCMF
{
	int n,m,s,t;
	vector<Edge>edges;
	vector<int>g[maxn];
	bool inq[maxn];
	int d[maxn];
	int p[maxn];
	int a[maxn];
	void init(int n,int s,int t)
	{
		this->n=n;
		this->s=s;
		this->t=t;
		edges.clear();
		for(int i = 0;i<=n;i++)g[i].clear();
	}
	void AddEdge(int from,int to,int cap,int cost)
	{
		edges.push_back(Edge(from,to,cap,0,cost));
		edges.push_back(Edge(to,from,0,0,-cost));
		m=edges.size();
		g[from].push_back(m-2);
		g[to].push_back(m-1);
	}
	bool BellmanFord(int &flow,int &cost)
	{
		for(int i = 0;i<n;i++)d[i]=INF;
		memset(inq,0,sizeof(inq));
		d[s]=0,a[s]=INF,inq[s]=1,p[s]=0;
		queue<int>q;
		q.push(s);
		while(!q.empty())
		{
			int u = q.front();
			q.pop();
			inq[u]=0;
			for(int i = 0;i<g[u].size();i++)
			{
                Edge &e = edges[g[u][i]];
				if(e.cap > e.flow && d[e.to]>d[u]+e.cost)
				{
					d[e.to]=d[u]+e.cost;
					p[e.to]=g[u][i];
					a[e.to]=min(a[u],e.cap-e.flow);
					if(!inq[e.to])
					{
						q.push(e.to);
						inq[e.to]=1;
					}
				}
			}
		}
		if(d[t]==INF)return false;
		flow+=a[t];
		cost+=a[t]*d[t];
		int u = t;
		while(u!=s)
		{
			edges[p[u]].flow+=a[t];
			edges[p[u]^1].flow-=a[t];
			u=edges[p[u]].from;
		}
		return true;
	}

	void Min_cost(int &flow,int &cost)
	{
		flow=0;cost=0;
		while(BellmanFord(flow,cost));
		//return cost;
	}
}mc;

int main()
{
    int T,cas=1;
	scanf("%d",&T);
	while(T--)
	{
		tot=0;
		int n,m;
		scanf("%d%d",&n,&m);
		int s = n*m*2+1;
		int t = n*m*2+2;
		mc.init(n*m*2+3,n*m*2+1,n*m*2+2);
		for(int i = 1;i<=n;i++)
			for(int j = 1;j<=m;j++)
			{
				int x;
				scanf("%d",&x);
				if(x==0)
				{
                    mc.AddEdge(s,(i-1)*m+j,1,0);       //s向为0的格子的入点建边
					mc.AddEdge((i-1)*m+j+n*m,t,1,0);   //0的格子的出点向t建边
					tot++;
				}
				else if (x&1)
					mc.AddEdge(s,(i-1)*m+j,1,0),tot++;      //s向奇数格子的入点建边
				else
					mc.AddEdge((i-1)*m+j+n*m,t,1,0);      //偶数格子的出边向t建边
			}
		for(int i = 2;i<=n;i++)
			for(int j = 1;j<=m;j++)
			{
				int x;
				scanf("%d",&x);
				int l = i-1;
				mc.AddEdge((l-1)*m+j,(i-1)*m+j+n*m,1,x);   //上一个点的入边向下一个点的出边建边
				mc.AddEdge((i-1)*m+j,(l-1)*m+j+n*m,1,x);
			}
		for(int i =1;i<=n;i++)
			for(int j = 2;j<=m;j++)
			{
				int x;
				scanf("%d",&x);
				int l = j-1;
				mc.AddEdge((i-1)*m+l,(i-1)*m+j+n*m,1,x);
				mc.AddEdge((i-1)*m+j,(i-1)*m+l+n*m,1,x);
			}
        int flow,cost;
		mc.Min_cost(flow,cost);
		printf("Case #%d: ",cas++);
		if(flow<tot)
			printf("-1\n");
		else
			printf("%d\n",cost);
	}
}

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   to an adjacent grid  , you have to pay for a certain amount of tolls. The cost is the same when goes back from   to  . 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  , which is the number of test cases. 
Each case begins with two integers,   and  , in a line 
The next   lines describe the board. Each line consists of   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   lines each have   nonnegative numbers, which describe the cost of vertical connection. The  -th number in  -th line is the cost when travels from grid   to 
The next   lines each have   nonnegative numbers, which describe the cost of horizontal connection. The  -th number in  -th line is the cost for a path to go from grid   to 
All the numbers, including the answer, can be represented using  2-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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值