网络最大流模板&SCOI2007蜥蜴

P3376 【模板】网络最大流

Dinic算法

#include <bits/stdc++.h>
using namespace std;
const int inf=1<<29;
const int N=10050;
const int M=100050;
int n,m,s,t,maxflow;
int fir[N],tot=1,nxt[M<<1],to[M<<1],w[M<<1],d[N];
queue<int> q;
void add(int x,int y,int z){
	nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;w[tot]=z;
	nxt[++tot]=fir[y];fir[y]=tot;to[tot]=x;w[tot]=0;
}
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c&15);c=getchar();}
	return cnt*f;
}
bool bfs_(){
	memset(d,0,sizeof(d));while(q.size())	q.pop();
	q.push(s);d[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=fir[x];i;i=nxt[i]){
			int y=to[i];
			if(w[i]&&!d[y]){
				q.push(y);
				d[y]=d[x]+1;
				if(y==t)	return 1;
			}
		}
	}
	return 0;
}
int dinic(int x,int flow){
	if(x==t)	return flow;
	int rest=flow,k;
	for(int i=fir[x];i&&rest;i=nxt[i]){
		int y=to[i];
		if(d[y]==d[x]+1&&w[i]){
			k=dinic(y,min(w[i],rest));
			if(!k)	d[y]=0;
			w[i]-=k;w[i^1]+=k;rest-=k;
		}
	}
	return flow-rest;
}
int main(){
	n=read(),m=read(),s=read(),t=read();
	tot=1;
	int u,v,val;
	for(int i=1;i<=m;i++){
		u=read(),v=read(),val=read();add(u,v,val);
	}
	int flow=0;
	while(bfs_()){
		while(flow=dinic(s,inf))	maxflow+=flow;
	}
	printf("%d",maxflow);
	return 0;
}

P2472 [SCOI2007]蜥蜴

重点在于建边:

1.建立一个虚的源点 s s s和一个虚的汇点 t t t
2. s s s朝每个有蜥蜴的石柱建一条长度为 1 1 1的边(计算有几只蜥蜴能使源点和汇点连通,即能跳出去)
3. t t t朝每个与边界距离不超过 d d d的点建一条长度为 i n f inf inf的边(不计数量的蜥蜴达到这些石柱后能跳出去)
4.将每个石柱拆成两个点,两个点之间建一条长度为 d d d的边(表示最多能通过几只蜥蜴)

然后跑一遍 D i n i c Dinic Dinic即可

#include <bits/stdc++.h>
using namespace std;
const int inf=1<<29;
const int N=25000;
const int M=350000;
queue<int> q;
char lir[N][N];
int d_[N];
int r,c,d;
int T,s;
int Map[60][60],a[60][60];
int fir[N],to[M<<1],w[M<<1],nxt[M<<1],tot=1;
int cnt;
void add(int x,int y,int z){
	nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;w[tot]=z;
	nxt[++tot]=fir[y];fir[y]=tot;to[tot]=x;w[tot]=0;
}
bool pd(int x,int y){if(x<=d||y<=d||(r-x+1)<=d||(c-y+1)<=d)	return 1;return 0;}
//注意判断是否超界的边界条件 
bool bfs_(){
	memset(d_,0,sizeof(d_));
	while(!q.empty())	q.pop();
	q.push(s);d_[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=fir[x];i;i=nxt[i]){
			int y=to[i];
			if(w[i]&&!d_[y]){d_[y]=d_[x]+1;q.push(y);if(y==T)	return 1;}
		}
	}
	return 0;
}
int maxflow=0;
int dinic(int x,int flow){
	if(x==T)	return flow;
	int rest=flow,k;
	for(int i=fir[x];i&&rest;i=nxt[i]){
		int y=to[i];
		if(w[i]&&d_[y]==d_[x]+1){
			k=dinic(y,min(rest,w[i]));
			if(!k)	d_[y]=0;
			w[i]-=k;w[i^1]+=k;rest-=k;
		}
	}
	return flow-rest;
}
int num=0;
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')	f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c&15);c=getchar();}
	return cnt*f;
}
int main(){
	s=0;
	r=read(),c=read(),d=read();
	T=r*c*2+5;
	for(int i=1;i<=r;i++){for(int j=1;j<=c;j++){a[i][j]=++num;}}
	for(int i=1;i<=r;i++){scanf("%s",lir[i]+1);}
	for(int i=1;i<=r;i++){for(int j=1;j<=c;++j){Map[i][j]=lir[i][j]^48;}}
	for(int i=1;i<=r;i++){scanf("%s",lir[i]+1);}
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			if(Map[i][j]){
				add(a[i][j],a[i][j]+r*c,Map[i][j]);
				if(pd(i,j)){add(a[i][j]+r*c,T,inf);}
			}
		}
	}
	for(int i=1;i<=r;++i){
		for(int j=1;j<=c;++j){
			for(int k=1;k<=r;++k){
				for(int p=1;p<=c;p++){
					if(i==k&&j==p)	continue;
					if(Map[i][j]&&Map[k][p])
						if((i-k)*(i-k)+(j-p)*(j-p)<=d*d){
							add(a[i][j]+r*c,a[k][p],inf);
						}
				}
			}
		}
	}
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			if(lir[i][j]=='L')	add(s,a[i][j],1),++cnt;
		}
	}
	int flow=0;
	while(bfs_()){
		while(flow=dinic(s,inf))	maxflow+=flow;
	}
	int ans=cnt-maxflow;
	printf("%d",ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值