bzoj1001(网络流+对偶图)

34 篇文章 0 订阅
11 篇文章 0 订阅

这道算是比较正宗的对偶图了。。

题意很明显是求最小割,然后由最大流最小割定理又可以转化成最大流。。

然而如果直接跑ispa明显会tle,10^6个点呢。。

那最大流要怎么求呢。。这就是对偶图的一个经典应用了。。

http://blog.sina.com.cn/s/blog_60707c0f01011fnn.html

对偶图概念和在最大流上的应该这篇文章讲的还算蛮清楚,其实就是对偶图上的边代表了从哪阻断原图上的路径,边的权值代表阻断的代价,所以直接跑最短路就可以了。。

以后看到阻挡路径的问题可以往对偶图想想。。。




/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 2000005
#define nm 7000000
#define pi 3.1415926535897931
using namespace std;
const ll inf=1000000000000000000;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
 





int n,m,id[1005][1005],tot,S,T;
ll d[NM];
struct edge{int t;ll v;edge*next;}e[nm],*h[NM],*o=e;
void _add(int x,int y,ll v){o->t=y;o->v=v;o->next=h[x];h[x]=o++;}
void add(int x,int y,ll v){_add(x,y,v);_add(y,x,v);}

struct tmp{
	int x;
	bool operator<(const tmp&o)const{return d[x]>d[o.x];}
};
void dij(){
	priority_queue<tmp>q;
	inc(i,1,T)d[i]=inf;
	q.push(tmp{S});d[S]=0;
	while(!q.empty()){
		int t=q.top().x;q.pop();
		link(t)if(d[j->t]>d[t]+j->v)d[j->t]=d[t]+j->v,q.push(tmp{j->t});
	}
}

int main(){
	freopen("data.in","r",stdin);
	n=read();m=read();
	if(n==1&&m==1)return 0*printf("0\n");
	if(n==1||m==1){
		int ans=read();
		while(~scanf("%d",&n))ans=min(ans,n);
		return 0*printf("%d\n",ans);
	}
	inc(i,1,n-1)inc(j,1,m-1)id[i][j]=++tot;
	S=tot<<1|1;T=S+1;
	inc(i,1,m-1)add(S,id[1][i],read());
	inc(i,1,n-2)inc(j,1,m-1)add(id[i][j]+tot,id[i+1][j],read());
	inc(j,1,m-1)add(id[n-1][j]+tot,T,read());
	inc(i,1,n-1){
		add(id[i][1]+tot,T,read());
		inc(j,1,m-2)add(id[i][j],id[i][j+1]+tot,read());
		add(id[i][m-1],S,read());
	}
	inc(i,1,n-1)inc(j,1,m-1)add(id[i][j],id[i][j]+tot,read());
	dij();
	printf("%lld\n",d[T]);
	return 0;
}






1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec   Memory Limit: 162 MB
Submit: 26913   Solved: 6858
[ Submit][ Status][ Discuss]

Description

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

 

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
1:(x,y)<==>(x+1,y) 
2:(x,y)<==>(x,y+1) 
3:(x,y)<==>(x+1,y+1) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6

Sample Output

14

HINT

 2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

Source

[ Submit][ Status][ Discuss]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值