HDU3870 Catch the Theves

本文介绍了一种将平面图转换为对偶图的方法,并利用该方法求解平面图的最小割问题。通过对偶图的最短路径计算,可以得到平面图的最小割值。文章提供了详细的算法实现,包括数据结构定义、初始化过程、主要工作流程和结果输出。

http://acm.hdu.edu.cn/showproblem.php?pid=3870

平面图转对偶图板题,方法见https://wenku.baidu.com/view/8f1fde586edb6f1aff001f7d.html

平面图的最小割等于对偶图的最短路

#include<bits/stdc++.h>
using namespace std;

const int maxl=410;
const int inf=2e9+10;

int n,m,s,t,tot,ans;
int a[maxl][maxl],num[maxl][maxl];
int dis[maxl*maxl];
struct ed
{
	int to,l;
};
vector<ed> e[maxl*maxl];
typedef pair<int,int> p;
priority_queue<p,vector<p>,greater<p> >q;
bool in[maxl*maxl];

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	s=1;t=(n-1)*(n-1)+2;
	for(int i=s;i<=t;i++)
		e[i].clear();
	tot=1;
	for(int i=1;i<n;i++)
		for(int j=1;j<n;j++)
			num[i][j]=++tot;
	for(int j=1;j<=n-1;j++)
	{
		e[s].push_back(ed{num[1][j],a[1][j]});
		e[num[1][j]].push_back(ed{s,a[1][j]});
	}
	for(int i=1;i<=n-1;i++)
	{
		e[s].push_back(ed{num[i][n-1],a[i][n]});
		e[num[i][n-1]].push_back(ed{s,a[i][n]});
	}
	for(int i=1;i<=n-1;i++)
		for(int j=1;j<=n-2;j++)
		{
			e[num[i][j]].push_back(ed{num[i][j+1],a[i][j+1]});
			e[num[i][j+1]].push_back(ed{num[i][j],a[i][j+1]});
		}
	for(int i=1;i<=n-2;i++)
		for(int j=1;j<=n-1;j++)
		{
			e[num[i][j]].push_back(ed{num[i+1][j],a[i+1][j]});
			e[num[i+1][j]].push_back(ed{num[i][j],a[i+1][j]});
		}
	for(int i=1;i<=n-1;i++)
	{
		e[num[i][1]].push_back(ed{t,a[i][1]});
		e[t].push_back(ed{num[i][1],a[i][1]});
	}
	for(int j=1;j<=n-1;j++)
	{
		e[num[n-1][j]].push_back(ed{t,a[n][j]});
		e[t].push_back(ed{num[n-1][j],a[n][j]});
	}
}

inline void mainwork()
{
	for(int i=s;i<=t;i++)
		in[i]=false,dis[i]=inf;
	dis[1]=0;q.push({dis[1],1});
	p d;int u,v;
	while(!q.empty())
	{
		d=q.top();q.pop();
		u=d.second;
		if(dis[u]!=d.first || in[u])
			continue;
		in[u]=true;
		for(ed b:e[u])
		{
			v=b.to;
			if(in[v] || dis[v]<=dis[u]+b.l)
				continue;
			dis[v]=dis[u]+b.l;
			q.push({dis[v],v});
		}
	}
	ans=dis[t];
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}	
	return 0;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值