0
点赞
收藏
分享

微信扫一扫

HDU 5520 Number Link(费用流)

快乐小码农 2023-06-12 阅读 42


题意:给你一个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);
	}
}


HDU 5520 Number Link(费用流)_i++

HDU 5520 Number Link(费用流)_出点_02

HDU 5520 Number Link(费用流)_i++_03

举报

相关推荐

0 条评论