BZOJ 1001 狼抓兔子 - 最短路

13 篇文章 0 订阅

传送门

题解

平面图最小割,转化为对偶图跑最短路即可。这个网上随便搜一下题解满天飞。

代码:

//BZOJ 1001
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<queue>
#define INF (LLONG_MAX/3)
#define P(i,j) (((i)-1)*(m-1)+(j))
#define Q(i,j) (P(i,j)+(n-1)*(m-1))
#define MAXN 2000100
#define MAXM 10000000
#define lint long long
using namespace std;
struct edges{
	int to,wgt,pre;
}e[MAXM];
int etop,h[MAXN];
struct node{
	int id;lint dist;
	node(int _i,int _d)
	{
		id=_i;
		dist=_d;
	}
	bool operator<(const node &n)const
	{
		return this->dist>n.dist;
	}
};
inline int add_edge(int u,int v,int w)
{
	etop++;
	e[etop].to=v;
	e[etop].wgt=w;
	e[etop].pre=h[u];
	h[u]=etop;
	return 0;
}
inline int build_edge(int u,int v,int w)
{
	add_edge(u,v,w);add_edge(v,u,w);return 0;
}
priority_queue<node> q;
lint dist[MAXN];bool vis[MAXN];
int dijkstra(int s,int t,int n)
{
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=n;i++) dist[i]=INF;
	while(!q.empty()) q.pop();
	q.push(node(s,dist[s]=0));
	while(!q.empty())
	{
		int x=q.top().id;q.pop();
		if(vis[x]) continue;vis[x]=true;
		for(int i=h[x];i;i=e[i].pre)
			if(!vis[e[i].to]&&dist[x]+e[i].wgt<dist[e[i].to])
			{
				dist[e[i].to]=dist[x]+e[i].wgt;
				q.push(node(e[i].to,dist[e[i].to]));
			}
	}
	return 0;
}
int main()
{
	int n,m;scanf("%d%d",&n,&m);
	int s=2*(n-1)*(m-1)+1,t=s+1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<m;j++)
		{
			int w,f=0;scanf("%d",&w);
			if(i==1) build_edge(s,P(i,j),w),f=1;
			if(i==n) build_edge(Q(i-1,j),t,w),f=1;
			if(!f) build_edge(P(i,j),Q(i-1,j),w);
		}
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++)
		{
			int w,f=0;scanf("%d",&w);
			if(j==1) build_edge(Q(i,j),t,w),f=1;
			if(j==m) build_edge(P(i,j-1),s,w),f=1;
			if(!f) build_edge(P(i,j-1),Q(i,j),w);
		}
	for(int i=1;i<n;i++)
		for(int j=1;j<m;j++)
		{
			int w;scanf("%d",&w);
			build_edge(P(i,j),Q(i,j),w);
		}
	dijkstra(s,t,2*(n-1)*(m-1)+2);
	printf("%lld\n",dist[t]);return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值