D84【模板】对偶图最短路 Dijkstra 算法 P4001 [ICPC-Beijing 2006] 狼抓兔子
D84【模板】对偶图最短路 Dijkstra 算法 P4001 [ICPC-Beijing 2006] 狼抓兔子_哔哩哔哩_bilibili
平面图 最小割 问题可以转化为对偶图 最短路 问题
P4001 [ICPC-Beijing 2006] 狼抓兔子 - 洛谷
思路
沿 SE 直线将平面分成两部分,左下建对偶图的起点 s,右上建对偶图的终点 t
每个三角形内建一点,第一行左下为 $1,3,5...$,右上为 $2,4,6...$,写个开点函数 get(x,y) = 2*x*(m-1)+2*y

建好对偶图后,跑一遍 Dijktra,答案就是 d[t]
点数 N = 2(n-1)(m-1) < 2e6,边数 M = 2[(n-1)(m-1)+(n-1)(m-1)+(n-1)(m-1)] = 6(n-1)(m-1) < 6e6
// 对偶图最短路 Dijkstra 算法 O(MlogN) #include<bits/stdc++.h> #define pii pair<int,int> using namespace std; const int N=2e6,M=6e6; 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,m,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 2*x*(m-1)+2*y; } int main(){ scanf("%d%d",&n,&m); s=0; t=2*(n-1)*(m-1)+1; //t对偶图终点编号 int w,v1,v2; for(int i=1;i<=n;i++)for(int j=1;j<m;j++){ //横边 scanf("%d",&w); v1=get(i-2,j)-1; v2=get(i-1,j); if(i==1) add(v2,t,w); else if(i==n) add(s,v1,w); else add(v1,v2,w),add(v2,v1,w); } for(int i=1;i<n;i++)for(int j=1;j<=m;j++){ //竖边 scanf("%d",&w); v1=get(i-1,j)-1; v2=v1-1; if(j==1) add(s,v1,w); else if(j==m) add(v2,t,w); else add(v1,v2,w),add(v2,v1,w); } for(int i=1;i<n;i++)for(int j=1;j<m;j++){ //斜边 scanf("%d",&w); v1=get(i-1,j)-1; v2=v1+1; add(v1,v2,w),add(v2,v1,w); } dijkstra(); printf("%d",d[t]); }
浙公网安备 33010602011771号