zoukankan      html  css  js  c++  java
  • P2046 [NOI2010] 海拔 对偶图最短路/最小割

    题意:

    戳这里

    分析:

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

    我们发现没有办法直接对这张图进行网络流建模,因为它要求的东西过于诡异,求 (displaystyle sum_{(e=u o 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
    ",dis[ed]);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    基于ObjectCache的应用
    数学趣题——验证角谷猜想
    数学趣题——递归法寻找最小值
    数学趣题——寻找同构数
    数学趣题——表示成两个数的平方和
    数学趣题——马克思手稿中的数学题
    数学趣题——具有特殊性质的数
    数学趣题——验证四方定理
    数学趣题——连续整数固定和问题
    数学趣题——验证尼克彻斯定理
  • 原文地址:https://www.cnblogs.com/youth518/p/14270807.html
Copyright © 2011-2022 走看看