传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=1001
平片图对偶图
面变成点,点变成面,公共边变为连边,权值保留。
给定一个起点终点(划分无限平面),最短路便是一条截了中间所有路径的路,即原图最小割。
刚开始有个地方搞错了空间太浪开了6倍炸掉了……然后以为不能预先直接存边做……于是用了这种手推式写法
#include<stdio.h>
#include<cstring>
#include<queue>
#define N 1005
using namespace std;
int n,m,ans=2147483647,dis[N<<1][N],e1[N][N],e2[N][N],e3[N][N];
bool f[N<<1][N];
struct P{int x,y;};
queue<P> Q;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) for (int j=1;j<m;j++) scanf("%d",e1[i]+j);
for (int i=1;i<n;i++) for (int j=1;j<=m;j++) scanf("%d",e2[i]+j);
for (int i=1;i<n;i++) for (int j=1;j<m;j++) scanf("%d",e3[i]+j);
if (n==1 && m==1){puts("0");return 0;}
if (n==1 || m==1)
{
if (n==1) for (int i=1;i<m;i++) ans=min(ans,e1[1][i]);
if (m==1) for (int i=1;i<n;i++) ans=min(ans,e2[i][1]);
printf("%d",ans);
return 0;
}
memset(dis,0x3f,sizeof(dis));
for (int i=1;i<m;i++) dis[1][i]=min(dis[1][i],e1[1][i]);
for (int i=1;i<n;i++) dis[i][m-1]=min(dis[i][m-1],e2[i][m]);
for (int i=1;i<m;i++) f[1][i]=1,Q.push((P){1,i});
for (int i=1;i<n;i++) f[i][m-1]=1,Q.push((P){i,m-1});
while (!Q.empty())
{
P u=Q.front();Q.pop();
int x=u.x,y=u.y;f[x][y]=0;
if (x<=n)
{
if (1<x && dis[x][y]+e1[x][y]<dis[x-1+n][y])
{
dis[x-1+n][y]=dis[x][y]+e1[x][y];
if (!f[x-1+n][y]) f[x-1+n][y]=1,Q.push((P){x-1+n,y});
}
if (y<m-1 && dis[x][y]+e2[x][y+1]<dis[x+n][y+1])
{
dis[x+n][y+1]=dis[x][y]+e2[x][y+1];
if (!f[x+n][y+1]) f[x+n][y+1]=1,Q.push((P){x+n,y+1});
}
if (dis[x][y]+e3[x][y]<dis[x+n][y])
{
dis[x+n][y]=dis[x][y]+e3[x][y];
if (!f[x+n][y]) f[x+n][y]=1,Q.push((P){x+n,y});
}
}
else
{
if (x<2*n-1 && dis[x][y]+e1[x-n+1][y]<dis[x-n+1][y])
{
dis[x-n+1][y]=dis[x][y]+e1[x-n+1][y];
if (!f[x-n+1][y]) f[x-n+1][y]=1,Q.push((P){x-n+1,y});
}
if (1<y && dis[x][y]+e2[x-n][y]<dis[x-n][y-1])
{
dis[x-n][y-1]=dis[x][y]+e2[x-n][y];
if (!f[x-n][y-1]) f[x-n][y-1]=1,Q.push((P){x-n,y-1});
}
if (dis[x][y]+e3[x-n][y]<dis[x-n][y])
{
dis[x-n][y]=dis[x][y]+e3[x-n][y];
if (!f[x-n][y]) f[x-n][y]=1,Q.push((P){x-n,y});
}
}
}
for (int i=1;i<n;i++) ans=min(ans,dis[i+n][1]+e2[i][1]);
for (int i=1;i<m;i++) ans=min(ans,dis[2*n-1][i]+e1[n][i]);
printf("%d",ans);
}