D85 对偶图最短路 Dijkstra 算法 P2046 [NOI2010] 海拔
D85 对偶图最短路 Dijkstra 算法 P2046 [NOI2010] 海拔_哔哩哔哩_bilibili
思路
贪心思考,所有格点的高度只能取 0 或 1,否则变差,并且对偶图的最短路径一定把平面图的格点分成两部分,
右下连通格点的高度均为 1,左上连通格点的高度均为 0,最短路径上的格边如果从 0 指向 1,那么边权有效,
这样,平面图的 最小割 转化为 对偶图的 最短路
类似 D83 模板,每个小方格内建一点,写个开点函数 get(x,y) = (x-1)*(n-1)+y
发现右手性质,从 s 到 t 沿着最短路径走,右手边一定是高度为 1 的格点,这样看图连对偶图的边就好

建好对偶图后,跑一遍 Dijktra,答案就是 d[t]
点数 N = 500*500+2 < 3e5,边数 M = 501*500*2*2 < 1.1e6
相关板子:
D84【模板】对偶图最短路 Dijkstra 算法 P4001 [ICPC-Beijing 2006] 狼抓兔子 - 董晓 - 博客园
// 对偶图最短路 Dijkstra 算法 O(MlogN) #include<bits/stdc++.h> #define pii pair<int,int> using namespace std; const int N=3e5,M=1.1e6; int to[M],ne[M],ww[M],h[N],idx; void add(int a,int b,int c){ to[++idx]=b,ww[idx]=c,ne[idx]=h[a],h[a]=idx; } int n,s,t; int d[N]; bool vis[N]; void dijkstra(){ memset(d,0x3f,sizeof d); d[s]=0; priority_queue<pii,vector<pii>,greater<pii> > q; q.push({0,s}); while(!q.empty()){ int u=q.top().second;q.pop(); if(vis[u])continue;vis[u]=1; for(int i=h[u];i;i=ne[i]){ int v=to[i],w=ww[i]; if(d[v]>d[u]+w){ d[v]=d[u]+w; q.push({d[v],v}); } } } } int get(int x,int y){ return (x-1)*(n-1)+y; } int main(){ cin>>n; n++; //变成边数 s=0; t=n*n+1; //t对偶图终点编号 int w,v1,v2; for(int i=1;i<=n;++i)for(int j=1;j<n;++j){ //从左到右 scanf("%d",&w); v1=get(i-1,j); //上点 v2=get(i,j); //下点 if(i==1) add(v2,t,w); else if(i==n) add(s,v1,w); else add(v2,v1,w); //右格点高,下点连上点 } for(int i=1;i<n;++i)for(int j=1;j<=n;++j){ //从上到下 scanf("%d",&w); v1=get(i,j-1); //左点 v2=get(i,j); //右点 if(j==1) add(s,v2,w); else if(j==n) add(v1,t,w); else add(v1,v2,w); //下格点高,左点连右点 } for(int i=1;i<=n;++i)for(int j=1;j<n;++j){ //从右到左 scanf("%d",&w); v1=get(i-1,j); //上点 v2=get(i,j); //下点 if(i==1) add(t,v2,w); else if(i==n) add(v1,s,w); else add(v1,v2,w); //左格点高,上点连下点 } for(int i=1;i<n;++i)for(int j=1;j<=n;++j){ //从下到上 scanf("%d",&w); v1=get(i,j-1); //左点 v2=get(i,j); //右点 if(j==1) add(v2,s,w); else if(j==n) add(t,v1,w); else add(v2,v1,w); //上格点高,右点连左点 } dijkstra(); printf("%d",d[t]); }
浙公网安备 33010602011771号