BZOJ 1001 [狼抓兔子]
题面
题意
给定一张 \(n \times m\) 的类网格图,求左上角到右下角的最大流。
题解
平面图上最大流转最短路。
题意可转化为求左上角到右下角的最大流。根据最大流最小割定理,网络流中最大流的值等于最小割的容量。由于本题中给出的网络流是平面图,可以用最短路在几何意义上算出最小割:
令题目给出的网络流图为 \(G\),源汇点分别是 \(s,t\)。从 \(t\) 到 \(s\) 连一条流量无限的边 \(e_0\),令连边后 \(G\) 的对偶图为 \(G'\),\(s',t'\) 分别是 \(G\) 被 \(e_0\) 分割的两个面在 \(G'\) 中对应的点,那么求 \(G\) 从 \(s\) 到 \(t\) 的最小割就可以等效为在 \(G'\) 中选取权值和尽可能小的边集,使得 \(s'\) 到 \(t'\) 联通,也就是求 \(s'\) 到 \(t'\) 的最短路。
形象地说,令 \(e'\) 是 \(e\) 的对应边,最小割的意义是割去权值和尽可能小的边使得 \(G\) 中没有 \(s\) 到 \(t\) 的通路。而如果把在 \(G'\) 中选择 \(e'\) 看作 \(G\) 中 割去 \(e\),那么相当于找到 \(G'\) 中 \(s'\) 到 \(t'\) 的一条通路,把图 \(G\) 剪开。显然,权值和最小的通路就是 \(s'\) 到 \(t'\) 的最短路。在 \(G'\) 中,点数和边数都是 \(O(nm)\) 的,Dijkstra 求解最短路,复杂度为 \(O(nm\log(nm))\)。
代码
#include<iostream>
#include<cstdio>
#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(){}
node(int u,ll d):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;
}

浙公网安备 33010602011771号