​传送门​

一看就是平面图最小割

用最大流肯定超时了

所以在网格左下角虚拟源点,右上角虚拟汇点

把每个封闭的 1 4 \frac{1}{4} 41的正方形当作一个点,按顺时针编号为 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4的顺序

那么相邻的区域连对应费用的边即可

使用 d i j s t r a dijstra dijstra堆优化可以通过

#include <bits/stdc++.h>
using namespace std;
const int inf = 2e9;
const int maxn = 2e7+10;
int n,m,s,t,x,y;
struct edge{
int to,nxt,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int w)
{
// cout << u << "->" << v << endl;
d[++cnt] = (edge){v,head[u],w},head[u] = cnt;
d[++cnt] = (edge){u,head[v],w},head[v] = cnt;
}
int dis[maxn],vis[maxn];
typedef pair<int,int>p;
void dijstra(int s)
{
for(int i=0;i<=t;i++) dis[i] = inf, vis[i] = 0;
priority_queue<p,vector<p>,greater<p> >q;
dis[s] = 0, q.push( p(0,s) );
while( !q.empty() )
{
int u = q.top().second; q.pop();
if( vis[u] ) continue;
vis[u] = 1;
for(int i=head[u];i;i=d[i].nxt )
{
int v = d[i].to;
if( dis[v]>dis[u]+d[i].w )
{
dis[v] = dis[u]+d[i].w;
q.push( p(dis[v],v) );
}
}
}
}
int main()
{
while( cin >> n >> m )
{
//第i行第j列编号为:(i-2)*m*4+
s = 0, t = n*m*4+1;
for(int i=1;i<=m;i++)//第一行
scanf("%d",&x), add( (i-1)*4+2,t,x);
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
int u = (i-2)*m*4+j*4;
int v = (i-1)*m*4+(j-1)*4+2;
add( u,v,x );
}
for(int i=1;i<=m;i++)
{
scanf("%d",&x); int u = (n-1)*m*4+i*4;
add(s,u,x);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m+1;j++)
{
scanf("%d",&x);
if( j==1 ) add(s,(i-1)*m*4+(j-1)*4+1,x);
else if( j==m+1 ) add( (i-1)*m*4+(m-1)*4+3,t,x);
else
{
int u = (i-1)*m*4+(j-2)*4+3;
add(u,u+2,x);
}
}
for(int i=1;i<=2*n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d%d",&x,&y);
int row = (i-1)/2+1;
if( i%2==1 )//这是上半部分
{
int u = (row-1)*m*4+(j-1)*4+2;
add(u,u-1,x); add(u,u+1,y);
}
else
{
int u = (row-1)*m*4+(j-1)*4+4;
add(u,u-3,x); add(u,u-1,y);
}
}
dijstra( s );
cout << dis[t] << '\n';
cnt = 1;
for(int i=0;i<=t;i++) head[i] = 0;
}
}