[SCOI2007] 蜥蜴 (最大流)
阿新 • • 發佈:2018-09-10
cpp 不同 數據 ont bits void href read 四川省
[SCOI2007] 蜥蜴
題目背景
07四川省選
題目描述
在一個r行c列的網格地圖中有一些高度不同的石柱,一些石柱上站著一些蜥蜴,你的任務是讓盡量多的蜥蜴逃到邊界外。
每行每列中相鄰石柱的距離為1,蜥蜴的跳躍距離是d,即蜥蜴可以跳到平面距離不超過d的任何一個石柱上。石柱都不穩定,每次當蜥蜴跳躍時,所離開的石柱高度減1(如果仍然落在地圖內部,則到達的石柱高度不變),如果該石柱原來高度為1,則蜥蜴離開後消失。以後其他蜥蜴不能落腳。任何時刻不能有兩只蜥蜴在同一個石柱上。
輸入輸出格式
輸入格式:
輸入第一行為三個整數r,c,d,即地圖的規模與最大跳躍距離。以下r行為石柱的初始狀態,0表示沒有石柱,1~3表示石柱的初始高度。以下r行為蜥蜴位置,“L”表示蜥蜴,“.”表示沒有蜥蜴。
輸出格式:
輸出僅一行,包含一個整數,即無法逃離的蜥蜴總數的最小值。
輸入輸出樣例
輸入樣例#1:
5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
輸出樣例#1:
1
說明
100%的數據滿足:$1<=r, c<=20, 1<=d<=4$
Solution
看到題目中的柱子每經一次高度-1馬上想到網絡流,每根柱子的高度就是網絡中一條邊的容量
其實網絡流的題目一般就是考建邊,建完以後套個最大流模板就行了
那麽怎麽建邊呢?
建一個源點S,匯點T(都是虛點)
- 考慮拆點,我們把一個柱子拆成入點和出點,把這兩個點之間建一條容量為柱子高度x的邊,代表這棵柱子最多只能經過x次
- 對於能夠到達地圖外的點,我們之間從它的出點向匯點建一條容量為inf的邊
- 枚舉兩個柱子,在地圖上歐幾裏得距離小於最大跳躍距離的點之間建一條容量為inf的邊
- 由源點向每個蜥蜴所在的點建一條容量為1的邊,代表這個點有一個蜥蜴
Code
#include<bits/stdc++.h> #define rg register #define il inline #define Min(a,b) (a)<(b)?(a):(b) #define Max(a,b) (a)>(b)?(a):(b) #define dis(a,b,x,y) ((x-a)*(x-a)+(y-b)*(y-b)) using namespace std; const int N=100,M=1e6+10; const int inf=2e9; void in(int &ans) { ans=0; char i=getchar(); while(i<'0' || i>'9') i=getchar(); while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar(); } int n,m,d,cur=1,ans; int S,T,NN,c1,c2,sum; char ch; int to[M<<1],nex[M<<1],head[M],cap[M<<1],lev[M],curr[M]; int c[N][N],p[N][N]; int l[M<<1],r[M<<1]; struct node { int l,r; }; vector<node>v; il void add(int a,int b,int c) { to[++cur]=b,nex[cur]=head[a]; cap[cur]=c,head[a]=cur; } il void read() { NN=n*m; T=2*n*m+1; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>ch; p[i][j]=++c1; c[i][j]=ch-'0'; if(c[i][j]) l[++c2]=i,r[c2]=j; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>ch; if(ch=='L') sum++,v.push_back((node){i,j}); } } il void init() { for(int i=1;i<=c2;i++) { add(p[l[i]][r[i]],p[l[i]][r[i]]+NN,c[l[i]][r[i]]); add(p[l[i]][r[i]]+NN,p[l[i]][r[i]],0); if(l[i]<=d || r[i]<=d || l[i]+d>n || r[i]+d>m) { add(p[l[i]][r[i]]+NN,T,inf); add(T,p[l[i]][r[i]]+NN,0); } } for(int i=1;i<=c2;i++) for(int j=1;j<=c2;j++) { if(dis(l[i],r[i],l[j],r[j])<=d*d && i!=j) { add(p[l[i]][r[i]]+NN,p[l[j]][r[j]],inf); add(p[l[j]][r[j]],p[l[i]][r[i]]+NN,0); } } for(int i=0;i<sum;i++) { add(S,p[v[i].l][v[i].r],1); add(p[v[i].l][v[i].r],S,0); } } bool bfs(int s,int t) { queue<int>q; memset(lev,-1,sizeof(lev)); q.push(s); lev[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=nex[i]) { if(lev[to[i]]==-1 && cap[i]>0) { lev[to[i]]=lev[u]+1; q.push(to[i]); } } } return lev[t]!=-1; } int dfs(int s,int f,int t,int rest=0) { if(s==t) return f; for(int i=head[s];i;i=nex[i]) { if(lev[to[i]]==lev[s]+1 && cap[i]>0) { int r=dfs(to[i],Min(cap[i],f-rest),t); if(r>0) rest+=r,cap[i]-=r,cap[i^1]+=r; } } if(!rest) lev[s]=-1; return rest; } int main() { in(n),in(m),in(d); read(); init(); while(bfs(S,T)) while(int c=dfs(S,inf,T)) ans+=c; printf("%d\n",sum-ans); return 0; }
博主蒟蒻,隨意轉載.但必須附上原文鏈接
http://www.cnblogs.com/real-l/
[SCOI2007] 蜥蜴 (最大流)