【题解】
先寻找每个点的最优高度范围:首先每个点的海拔不可能比周围四个点都高或都低,然后设某点高度为x,假设围四个点高度已知,随便考虑几种情况,可以发现:总体力值关于x单调(增或减)
因此可以得出结论:每个点的海拔都与周围的某个点相同
=> 可以推出(我是猜出)每个点高度都是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;
}