【题解】
先寻找每个点的最优高度范围:=> 可以推出(我是猜出)每个点高度都是0或1,且按高度标记每个点后,图上只有2个连通块
然后就是熟悉的最小割转最短路了,给每个域编号后建新图,要注意建的有向边的方向(见图)
比如:规定两个上下相邻、"期望海拔方案"为上0下1的点的连边,对应新图中的边的方向为:从右到左
【代码】
#include<stdio.h> #include<stdlib.h> typedef long long LL; LL w[2000000]={0},d[3000000]={0},heap[300000]={0};//heap[i]:堆的第i个位置对应元素的序号 int v[2000000]={0},first[300000]={0},next[2000000]={0},pos[300000]={0};//pos[i]:第i个元素在堆中的的序号,heap[]与pos[]作用相反 const LL INF=1000000000000000000ll; int e=0,node; void jh_heap(int a,int b) { int t=pos[heap[a]];//"先交换pos再heap"不必须 pos[heap[a]]=pos[heap[b]]; pos[heap[b]]=t; t=heap[a]; heap[a]=heap[b]; heap[b]=t; } void tj(int x,int y,int z) { v[++e]=y; w[e]=(LL)z; next[e]=first[x]; first[x]=e; } void tz(int x) { int i; for(i=x;i>1;i/=2) { if(d[heap[i/2]]>d[heap[i]]) jh_heap(i/2,i); else return; } } void sc() { int i=1; jh_heap(1,node); node--; while(i*2<=node) { i*=2; if(i+1<=node&&d[heap[i]]>d[heap[i+1]]) i++; if(d[heap[i/2]]>d[heap[i]]) jh_heap(i/2,i); else return; } } int main() { int n,i,j,s,t,x; scanf("%d",&n); s=n*n+1; t=s+1; for(i=1;i<=n+1;i++)//西->东(左0右1),从上到下建边 for(j=1;j<=n;j++) { scanf("%d",&x); if(i==1) tj(s,j,x); if(i>1&&i<=n) tj((i-2)*n+j,(i-1)*n+j,x); if(i>n) tj((i-2)*n+j,t,x); } for(i=1;i<=n;i++)//北->南(上0下1),从右到左建边 for(j=1;j<=n+1;j++) { scanf("%d",&x); if(j==1) tj((i-1)*n+j,t,x); if(j>1&&j<=n) tj((i-1)*n+j,(i-1)*n+j-1,x); if(j>n) tj(s,i*n,x); } for(i=1;i<=n+1;i++)//东->西(左1右0),从下到上建边 for(j=1;j<=n;j++) { scanf("%d",&x); if(i>1&&i<=n) tj((i-1)*n+j,(i-2)*n+j,x); } for(i=1;i<=n;i++)//南->北(上1下0),从左到右建边 for(j=1;j<=n+1;j++) { scanf("%d",&x); if(j>1&&j<=n) tj((i-1)*n+j-1,(i-1)*n+j,x); } heap[1]=s; pos[s]=1; for(i=1;i<=n*n;i++) { d[i]=INF; heap[i+1]=i; pos[i]=i+1; } d[t]=INF; node=heap[t]=pos[t]=t; for(i=1;i<t;i++) { x=heap[1]; sc(); for(j=first[x];j!=0;j=next[j]) if(d[v[j]]>d[x]+w[j]) { d[v[j]]=d[x]+w[j]; tz(pos[v[j]]); } } printf("%lld",d[t]); return 0; }