对于这道题,是一个裸的求一张图最小割的问题,可是数据太大,dinic过不了,注意到题目中的图是平面图,因此我们可以通过将平面图转化为对偶图的形式在对偶图中跑最短路,这样就可以用SPFA或堆优化的dijkstra来做了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define maxn 2000005
int last[3*maxn],other[3*maxn],pre[3*maxn],len[3*maxn];
int a[1001][1001],b[1001][1001],c[1001][1001];
int l,tot,n,m,dis[maxn],que[2*maxn],vis[maxn];
void connect(int x,int y,int z)
{
//printf("%d %d %d\n",x,y,z);
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
len[l]=z;
//printf("%d %d %d\n",x,y,z);
}
void spfa(int s)
{
memset(dis,53,sizeof dis);
int h=0,t=1;
que[1]=s;dis[s]=0;
while (h!=t)
{
h=h%2000000+1;
int u=que[h];vis[u]=0;
for (int p=last[u];p;p=pre[p])
{
int v=other[p];
if (dis[v]>dis[u]+len[p])
{
dis[v]=dis[u]+len[p];
if (!vis[v])
{
int temp=dis[que[h%2000000+1]];
if (dis[v]<temp)
{
que[h]=v;
h--;
if (h<=0) h=2000000;
}
else
{
t=t%2000000+1;
que[t]=v;
}
vis[v]=1;
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<m;j++) scanf("%d",&a[i][j]);
for (int i=1;i<n;i++)
for (int j=1;j<=m;j++) scanf("%d",&b[i][j]);
for (int i=1;i<n;i++)
for (int j=1;j<m;j++) scanf("%d",&c[i][j]);
int s=0,t=(n-1)*(m-1)*2+1;
for (int i=1;i<n;i++)
for (int j=1;j<m;j++)
{
int ok1x=0,ok2x=0,ok3x=0;
int ok1y=0,ok2y=0,ok3y=0;
int x=(i-1)*(m-1)*2+2*(j-1)+1;
int y=x+1;
if (i==1)
{
connect(x,t,a[1][j]);
ok1x=1;
}
if (i==n-1)
{
connect(s,y,a[n][j]);
ok2y=1;
}
if (j==1)
{
connect(s,y,b[i][1]);
ok3y=1;
}
if (j==m-1)
{
connect(x,t,b[i][m]);
ok2x=1;
}
connect(y,x,c[i][j]);
if (!ok1x) connect(x,x-(m-1)*2+1,a[i][j]);
if (!ok2x) connect(x,x+3,b[i][j+1]);
if (!ok2y) connect(y,y+(m-1)*2-1,a[i+1][j]);
if (!ok3y) connect(y,y-3,b[i][j]);
}
for (int i=0;i<=t;i++) dis[i]=1e9;
spfa(s);
if (n==1)
for (int i=1;i<m;i++) dis[t]=min(dis[t],a[1][i]);
if (m==1)
for (int i=1;i<n;i++) dis[t]=min(dis[t],b[i][1]);
printf("%d\n",dis[t]);
return 0;
}