D84【模板】对偶图最短路 Dijkstra 算法 P4001 [ICPC-Beijing 2006] 狼抓兔子

D84【模板】对偶图最短路 Dijkstra 算法 P4001 [ICPC-Beijing 2006] 狼抓兔子_哔哩哔哩_bilibili

 

平面图 - OI Wiki

平面图 最小割 问题可以转化为对偶图 最短路 问题

 

P4001 [ICPC-Beijing 2006] 狼抓兔子 - 洛谷

思路

沿 SE 直线将平面分成两部分,左下建对偶图的起点 s,右上建对偶图的终点 t

每个三角形内建一点,第一行左下为 $1,3,5...$,右上为 $2,4,6...$,写个开点函数 get(x,y) = 2*x*(m-1)+2*y

 image image

建好对偶图后,跑一遍 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]);
}
 

 

posted @ 2026-02-24 09:03  董晓  阅读(112)  评论(0)    收藏  举报