测试地址:狼抓兔子
做法:本题需要用到平面图最小割转最短路。
注意到题目中要求一个平面图的最小割,然而这个图点数太多,我们不可能直接用网络流求解,但是我们注意到,如果在平面图中每两个相邻区域之间连双向边(我们把右、上边界和左、下边界看做两个不相邻的平面区域),边的长度为这两个区域的公共边的权值,这时候我们发现,每一个割都对应了一条从右、上边界到左、下边界的路径,因此按这样建图之后跑最短路即可,因为SPFA会被卡,因此用Dijkstra实现即可,时间复杂度为
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define inf 1000000000
using namespace std;
int n,m,x,first[2000010]={0},tot=0,t,dis[2000010];
struct edge {int v,d,next;} e[12000010];
bool vis[2000010]={0};
struct point
{
int val,id;
bool operator < (point a) const
{
return val>a.val;
}
};
priority_queue <point> Q;
void insert(int a,int b,int d)
{
e[++tot].v=b;
e[tot].d=d;
e[tot].next=first[a];
first[a]=tot;
}
void dijkstra()
{
point now,nxt;
now.val=0,now.id=0;
vis[0]=1,dis[0]=0;
for(int i=1;i<=t;i++) dis[i]=inf;
for(int i=first[0];i;i=e[i].next)
{
nxt.val=e[i].d;
nxt.id=e[i].v;
dis[e[i].v]=e[i].d;
Q.push(nxt);
}
while(!Q.empty())
{
now=Q.top();
while(vis[now.id]&&!Q.empty()) Q.pop(),now=Q.top();
if (Q.empty()) break;
vis[now.id]=1;
for(int i=first[now.id];i;i=e[i].next)
if (dis[e[i].v]>dis[now.id]+e[i].d)
{
dis[e[i].v]=dis[now.id]+e[i].d;
nxt.id=e[i].v;
nxt.val=dis[e[i].v];
Q.push(nxt);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
t=2*(n-1)*(m-1)+1;
int minx=inf;
for(int i=1;i<m;i++)
{
scanf("%d",&x);
minx=min(x,minx);
insert(0,i,x);
}
for(int i=1;i<n-1;i++)
{
int s=(2*i-1)*(m-1);
for(int j=1;j<m;j++)
{
scanf("%d",&x);
minx=min(minx,x);
insert(s+j,s+j+m-1,x);
insert(s+j+m-1,s+j,x);
}
}
for(int i=1;i<m;i++)
{
scanf("%d",&x);
minx=min(minx,x);
insert((2*n-3)*(m-1)+i,t,x);
}
for(int i=1;i<n;i++)
{
int s=(2*i-1)*(m-1);
scanf("%d",&x);
minx=min(minx,x);
insert(s+1,t,x);
for(int j=2;j<m;j++)
{
scanf("%d",&x);
minx=min(minx,x);
insert(s+j,s+j-m,x);
insert(s+j-m,s+j,x);
}
scanf("%d",&x);
minx=min(minx,x);
insert(0,s,x);
}
for(int i=1;i<n;i++)
{
int s=(2*i-1)*(m-1);
for(int j=1;j<m;j++)
{
scanf("%d",&x);
minx=min(minx,x);
insert(s+j,s+j-m+1,x);
insert(s+j-m+1,s+j,x);
}
}
if (n==1||m==1) {printf("%d",minx);return 0;}
dijkstra();
printf("%d",dis[t]);
return 0;
}