洛谷$P2046\ [NOI2010]$海拔 网络流+对偶图

正解:网络流+对偶图

解题报告:

传送门$QwQ$

$umm$之前省选前集训的时候叶佬考过?然而这和我依然不会做有什么关系呢$kk$

昂这题首先要两个结论?第一个是说每个位置的海拔一定是0/1,还一个是说0/1一定都是连通块$QwQ$

瞎证下?$QwQ$.

结论一:若存在海拔大于1的点,下坡不变,上坡代价增加,显然改为1更优

      若存在海拔在0到1之间的点,同样理由,发现改为0更优

结论二有点显然的亚子,,,懒得证了趴$QwQ$

欧克然后现在这道题就变成一个最小割了?

但是$n$的范围是500,,,显然会$T$昂$QAQ$.

然后就考虑,转对偶图求最短路

恩因为只是个技巧类的姿势点所以我就懒得写学习笔记辣,网上随便一搜就成鸭$QwQ$

简单总结下就,平面图上的最大流等价于对偶图的最短路,构建对偶图的方法是把每对相邻面连接起来,边权为穿过的边界的流量.跑个最短路.$over$

然后由上面两个结论得这个图确实是个平面图,所以转化成对偶图求个最短路就做完了$QwQ$?

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define fi first
#define sc second
#define gc getchar()
#define mp make_pair
#define P pair<int,int>
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];i;i=edge[i].nxt)

const int N=2500+10;
int n,ed_cnt,head[N*N],S,T,dis[N*N];
struct ed{int to,nxt,wei;}edge[N*N*20];
bool vis[N*N];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il void ad(ri x,ri y,ri z){edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;}
il int nam(ri x,ri y){if(!x)return T;if(y>n)return T;if(!y)return S;if(x>n)return S;return (x-1)*n+y;}
il void dij()
{
    priority_queue< P,vector<P>,greater<P> >Q;Q.push(mp(0,S));memset(dis,63,sizeof(dis));
    while(!Q.empty())
    {
        ri nw=Q.top().sc,diss=Q.top().fi;Q.pop();if(vis[nw])continue;vis[nw]=1;dis[nw]=diss;
        e(i,nw)if(!vis[t(i)])Q.push(mp(dis[nw]+w(i),t(i)));
    }
}

int main()
{
    n=read();T=n*n+1;
    rp(i,1,n+1)rp(j,1,n)ad(nam(i-1,j),nam(i,j),read());
    rp(i,1,n)rp(j,1,n+1)ad(nam(i,j),nam(i,j-1),read());
    rp(i,1,n+1)rp(j,1,n)ad(nam(i,j),nam(i-1,j),read());
    rp(i,1,n)rp(j,1,n+1)ad(nam(i,j-1),nam(i,j),read());
    dij();printf("%d\n",dis[T]);
    return 0;
}
数组不用那么大,是我之前脑抽想错了🙈🙈🙈

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值