1001: [BeiJing2006]狼抓兔子
题目的意思是用最少的狼封闭所有道路(即切断起点和终点),典型的最小割模型。转化一下,就给你一个二分图,让你求最大流。点数多达1000000,边数6000000条,用普通的网络流是没法过的。
那么把它转化为对偶图, 详见周东最大最小定理的论文,就这样建图。
WA了一发后,发现一定要注意m==1 || n==1时的特判,因为对偶图满足的是欧拉定理,而当它是一条线的时候,是不满足的。
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 2000020;
const int maxm = 6000020;
const int inf = 1<<30;
struct node{
int d,u;
bool operator < (const node &rhs)const{
return d > rhs.d;
}
};
struct edge{
int v,x;
edge *nxt;
}*cur,*head[maxn],meo[maxm];
int m,n,dis[maxn],done[maxn];
void adde(int u,int v,int x){
cur->v = v;
cur->x = x;
cur->nxt = head[u];
head[u] = cur++;
cur->v = u;
cur->x = x;
cur->nxt = head[v];
head[v] = cur++;
}
void read(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
void Dijkstra(int s){
priority_queue <node>q;
for(int i = 0;i <= m*n*2+2;++i)dis[i] = inf;
dis[s] = 0;
q.push((node){dis[s],s});
while(!q.empty()){
node p = q.top();q.pop();
int u = p.u;
if(done[u])continue;
done[u] = true;
for(edge *it = head[u];it;it = it->nxt){
int v = it->v;
if(dis[v] > dis[u]+it->x){
dis[v] = dis[u]+it->x;
q.push((node){dis[v],v});
}
}
}
}
int address(int x,int y){
return ((x-1)*(m-1)+y)*2-1;
}
int main(){
cur = meo;
scanf("%d%d",&n,&m);
const int S = 0;
const int T = 2*n*m+2;
int x,ans = inf;
if (n == 1 || m == 1) {
if (n > m) swap(n, m);
int ans = inf;
for (int i = 1; i < m; ++i){
read(x);
ans = min(ans,x);
}
printf("%d\n",ans);
exit(0);
}
for(int i = 1;i <= n;++i){
for(int j = 1;j < m;++j){
read(x);
if(i == 1){
adde(address(i,j),S,x);
}
else if(i == n){
adde(address(i-1,j)+1,T,x);
}
else{
adde(address(i-1,j)+1,address(i,j),x);
}
}
}
for(int i = 1;i < n;++i){
for(int j = 1;j <= m;++j){
read(x);
if(j == 1){
adde(address(i,j)+1,T,x);
}
else if(j == m){
adde(address(i,j-1),S,x);
}
else{
adde(address(i,j-1),address(i,j)+1,x);
}
}
}
for(int i = 1;i < n;++i){
for(int j = 1;j < m;++j){
read(x);
int pos = address(i,j),pos2 = address(i,j)+1;
adde(address(i,j),address(i,j)+1,x);
}
}
Dijkstra(S);
printf("%d\n",dis[T]);
return 0;
}