题面
题解
平面图上网络流转最短路。
题意可转化为求左上角到右下角的最大流。根据最大流最小割定理,网络流中最大流的值等于最小割的容量。由于本题中给出的网络流是平面图,可以用最短路在几何意义上算出最小割:
对每一个封闭区域 \(u\) 建点 \(u'\),对每两个相接的封闭区域 \(u,v\) 的公共边 \(e\) 建边 \(e'\) 连接 \(u',v'\),\(e'\) 的权值等于 \(e\) 的流量,如果把选取 \(e'\) 看作割断 \(e\),那么求网络流的最小割就可以等效为选取权值和尽可能小的 \(e'\),使得图的左下方和右上方联通,而这个问题可以用最短路来解决。复杂度 \(O(nm\log(nm))\)。
代码
查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int maxn=2e6+5,maxm=6e6+5;
int hea[maxn],nex[maxm],to[maxm],wei[maxm],tot;
struct node{
int u; ll d;
node(int u=0,ll d=0):u(u),d(d){}
};
bool operator < (const node &a,const node &b){
return a.d>b.d;
}
ll dis[maxn];
priority_queue<node> que;
void dijkstra(int s,int n){
int i,ed;
int u,v,w;
ll d;
node tmp;
for (i=0;i<n;i++) dis[i]=inf;
while (!que.empty()) que.pop();
que.push(node(s,dis[s]=0));
while (!que.empty()){
tmp=que.top(); que.pop(); u=tmp.u; d=tmp.d;
if (d>dis[u]) continue;
for (ed=hea[u];ed;ed=nex[ed]){
v=to[ed]; w=wei[ed];
if (dis[v]>d+w) que.push(node(v,dis[v]=(d+w)));
}
}
}
int n,m,s,t;
inline int getid(int x,int y,int z){
if (x<1||y>=m) return s;
if (x>=n||y<1) return t;
return (x-1)*(m-1)*2+y*2-z;
}
void add(int u,int v,int w){
tot++;
nex[tot]=hea[u];
hea[u]=tot;
to[tot]=v;
wei[tot]=w;
}
int main(){
int i,j;
int u,v,w;
scanf("%d%d",&n,&m); s=0; t=(n-1)*(m-1)*2+1; tot=0;
for (i=1;i<=n;i++) for (j=1;j<m;j++){
scanf("%d",&w);
u=getid(i-1,j,1); v=getid(i,j,0);
add(u,v,w); add(v,u,w);
}
for (i=1;i<n;i++) for (j=1;j<=m;j++){
scanf("%d",&w);
u=getid(i,j-1,0); v=getid(i,j,1);
add(u,v,w); add(v,u,w);
}
for (i=1;i<n;i++) for (j=1;j<m;j++){
scanf("%d",&w);
u=getid(i,j,1); v=getid(i,j,0);
add(u,v,w); add(v,u,w);
}
dijkstra(s,t+1);
printf("%lld\n",dis[t]);
return 0;
}