P2046 [NOI2010] 海拔 对偶图最短路/最小割

题意:

戳这里

分析:

怎么说呢,看了半个小时都不会,题解一句话给我点醒了/kk

我们发现没有办法直接对这张图进行网络流建模,因为它要求的东西过于诡异,求 \(\displaystyle \sum_{(e=u\to v)} w(e)*max(0,h_u-h_v)\) 这个东西网络流做不了呀,然后我就不会了,就去瞄了一眼题解,看到了一句话, 我么要尽可能使得高度差变小,**理想状态下所有的点高度都是 \(0\) ,但由于源汇点必定存在高度差,所以最终这张图的状态就是左上角高度全为 \(0\) ,右下角高度全部为 \(1\) **,中间存在一条 \(0,1\) 的分界线,答案就是这些边的权值 , 这个值我们可以求一遍最小割或者建出对偶图直接从右上向左下跑最短路就可以了

tip:

我原本以为右上向左下跑最短路,只与 自西向东和自北向南 两个方向有关,但实际上可能存在轮廓线绕了个弯的情况,所以四个方向的边我们都得建出来,对偶图的建图很简单,就是将原图的边 顺/逆时针旋转 \(90'\) 就可以了

代码:

码量不大很良心

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second

using namespace std;

namespace zzc
{
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	const int maxn = 2.6e5+5;
	const int maxm = 1.2e6+5;
	int n,st,ed,cnt=0;
	int head[maxn],len[5][501][501];
	bool vis[maxn];
	long long dis[maxn];
	struct edge
	{
		int to,nxt,val;
	}e[maxm];
	priority_queue<pair<long long ,int> > q;
	
	void add(int u,int v,int w)
	{
		e[++cnt].to=v;
		e[cnt].val=w;
		e[cnt].nxt=head[u];
		head[u]=cnt;
	}
	
	inline int id(int x,int y)
	{
		return (x-1)*(n+2)+y;
	}
	
	void init()
	{
		for(int i=1;i<=n+1;i++) for(int j=1;j<=n;j++) len[1][i][j]=read();
		for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) len[2][i][j]=read();
		for(int i=1;i<=n+1;i++) for(int j=1;j<=n;j++) len[3][i][j]=read();
		for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) len[4][i][j]=read();
		
		for(int i=2;i<=n+1;i++) add(st,id(1,i),0),add(st,id(i,n+2),0),add(id(i,1),ed,0),add(id(n+2,i),ed,0);
		for(int i=1;i<=n+1;i++) for(int j=1;j<=n;j++) add(id(i,j+1),id(i+1,j+1),len[1][i][j]);
		for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) add(id(i+1,j+1),id(i+1,j),len[2][i][j]);
		for(int i=1;i<=n+1;i++) for(int j=1;j<=n;j++) add(id(i+1,j+1),id(i,j+1),len[3][i][j]);
		for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) add(id(i+1,j),id(i+1,j+1),len[4][i][j]);
	}
	
	void dijkstra()
	{
		memset(dis,0x3f,sizeof(dis));
		dis[st]=0;
		q.push(mk(0,st));
		while(!q.empty())
		{
			int u=q.top().sec;q.pop();
			if(vis[u]) continue;
			vis[u]=true;
			for(int i=head[u];i;i=e[i].nxt)
			{
				int v=e[i].to;
				if(dis[v]>dis[u]+e[i].val)
				{
					dis[v]=dis[u]+e[i].val;
					q.push(mk(-dis[v],v));
				}
			}
		}
	}
	
	void work()
	{
		n=read();st=id(1,n+2);ed=id(n+2,1);
		init();
		dijkstra();
		printf("%lld\n",dis[ed]);
	}

}

int main()
{
	zzc::work();
	return 0;
}

posted @ 2021-01-13 10:41  youth518  阅读(94)  评论(0编辑  收藏  举报