BZOJ 1001 狼抓兔子 (最大流转最短路) - xgtao -

狼抓兔子

 

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;
}

  

 

posted @ 2016-07-23 08:31  xgtao984  阅读(225)  评论(0编辑  收藏  举报