【网络流】【BZOJ1006】【SCOI2007】蜥蜴
学弟@lher在周末训练赛中出的题目的原题(这个人拿省选题来当作提高组模拟,太丧了。。。)
题意简析:看题目:)
解题思路:题目显然是最大流。
首先拆点将点权变为边权,然后按照题意对于所有有跳板的点向可以跳到的点连一条权值为inf的边,对于能够跳出地图边界的点,将它与汇点连一条权值为inf的边。对于有蜥蜴的点,从源点向这个点连一条权值为1的边,然后跑一次最大流,答案就是蜥蜴数-最大流。
AC代码:
#include<stdio.h> #include<iostream> #include<cmath> #include<cstring> #include<string> #include<algorithm> #define ll long long #define inf 0x7fffffff using namespace std; struct zxy{ int next,to,v; }edge[1000005]; int n,m,d,head[10005],iter[10005],lev[10005],que[100005],cnt=1,mz=0; bool b[55][55]; inline int getno(int x,int y){ return (x-1)*m+y;} inline int getdis(int x,int y,int a,int b){ return ceil(sqrt((x-a)*(x-a)+(y-b)*(y-b)));} inline void ins(int x,int y,int l){edge[++cnt].next=head[x],head[x]=cnt,edge[cnt].to=y,edge[cnt].v=l;} inline int in(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } inline bool bfs(int s,int e){ memset(lev,-1,sizeof(lev)); int t=1,h=0; que[1]=s; lev[s]=0; do{ h++; int k=head[que[h]]; while(k){ if (lev[edge[k].to]==-1&&edge[k].v){ lev[edge[k].to]=lev[que[h]]+1; que[++t]=edge[k].to; } k=edge[k].next; } }while(h<t); return lev[e]!=-1; } inline int dfs(int u,int v,int f){ if (u==v) return f; int used=0,k=head[u]; while(k){ if (edge[k].v&&lev[edge[k].to]==lev[u]+1){ int w=dfs(edge[k].to,v,min(edge[k].v,f-used)); used+=w; edge[k].v-=w; edge[k^1].v+=w; if (used==f) return used; } k=edge[k].next; } return used; } int dinic(int s,int t){ int flow=0; while(bfs(s,t)) flow+=dfs(s,t,inf); return flow; } void init(){ n=in(),m=in(),d=in(); for (int i=1; i<=n; ++i){ for (int j=1; j<=m; ++j){ int x=getchar()-'0',no=getno(i,j); if (x) ins(no,no+n*m,x),ins(no+n*m,no,0),b[i][j]=1; } getchar(); } for (register int i=1; i<=n; ++i){ for(register int j=1; j<=m; ++j) if (getchar()=='L') ++mz,ins(0,getno(i,j),1),ins(getno(i,j),0,0); getchar(); } for (register int i=1; i<=n; ++i) for (register int j=1; j<=m; ++j) if(b[i][j]){ if (i-d<1||i+d>n||j-d<1||j+d>m) ins(getno(i,j)+n*m,n*m*2+1,inf),ins(n*m*2+1,getno(i,j)+n*m,0); for (int k=(i-d<1?1:i-d); k<=(i+d>n?n:i+d); ++k) for (int t=(j-d<1?1:j-d); t<=(j+d>m?m:j+d); ++t) if (b[k][t]&&getdis(i,j,k,t)<=d&&(i!=k||j!=t)) ins(getno(i,j)+n*m,getno(k,t),inf),ins(getno(k,t),getno(i,j)+n*m,0); } } int main(){ init(); printf("%d",mz-dinic(0,2*n*m+1)); return 0; }
本文由Melacau编写,Melacau代表M星向您问好,如果您不是在我的博客http://www.cnblogs.com/Melacau上看到本文,请您向我联系,email:13960948839@163.com.