题面太长啦,请诸位自行品尝—>海拔
分析:
这是我见过算法比较明显的最小割题目了,很明显对于某一条简单路径,海拔只会有一次变换。
而且我们要最终使变换海拔的边权值和最小。
我们发现变换海拔相当于将图割开,左上右下两个点分别属于两个不同的集合,那这就是一个很形象的最小割模型。
我们只需要平面图转转对偶图,将图中每个面变成点,连边跑最短路即可。
转换的细节可能有些麻烦,大家慢慢理解。
代码:
1 #include<bits/stdc++.h> 2 #define pi pair<int,int> 3 #define mp(a,b) make_pair(a,b) 4 #define ms(a,x) memset(a,x,sizeof(a)) 5 using namespace std; 6 const int N=250005;int S,T,ans; 7 struct node{int y,z,nxt;}e[N*8]; 8 priority_queue<pi>q;int h[N],c=1; 9 int d[N],vis[N],n,m,nm[505][505]; 10 void add(int x,int y,int z){ 11 e[++c]=(node){y,z,h[x]};h[x]=c; 12 } int main(){ 13 scanf("%d",&n);S=0;T=n*n+1; 14 for(int i=1;i<=n;i++) 15 nm[0][i]=nm[i][n+1]=S, 16 nm[i][0]=nm[n+1][i]=T; 17 for(int i=1;i<=n;i++) 18 for(int j=1;j<=n;j++) 19 nm[i][j]=n*(i-1)+j; 20 for(int i=0;i<=n;i++) 21 for(int j=1,x;j<=n;j++) 22 scanf("%d",&x),add(nm[i][j],nm[i+1][j],x); 23 for(int i=1;i<=n;i++) 24 for(int j=0,x;j<=n;j++) 25 scanf("%d",&x),add(nm[i][j+1],nm[i][j],x); 26 for(int i=0;i<=n;i++) 27 for(int j=1,x;j<=n;j++) 28 scanf("%d",&x),add(nm[i+1][j],nm[i][j],x); 29 for(int i=1;i<=n;i++) 30 for(int j=0,x;j<=n;j++) 31 scanf("%d",&x),add(nm[i][j],nm[i][j+1],x); 32 ms(d,0x3f);d[S]=0;q.push(mp(0,S)); 33 while(!q.empty()){ 34 int x=q.top().second;q.pop(); 35 if(vis[x]) continue;vis[x]=1; 36 for(int i=h[x],y;i;i=e[i].nxt) 37 if(d[y=e[i].y]>d[x]+e[i].z) 38 d[y]=d[x]+e[i].z,q.push(mp(-d[y],y)); 39 } printf("%d ",d[T]);return 0; 40 }