BZOJ1565:[NOI2009]植物大战僵尸——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1565
https://www.luogu.org/problemnew/show/P2805
Plants vs. Zombies(PVZ)是最近十分風靡的一款小游戲。Plants(植物)和Zombies(僵尸)是游戲的主角,其中Plants防守,而Zombies進攻。該款游戲包含多種不同的挑戰系列,比如Protect Your Brain、Bowling等等。其中最為經典的,莫過于玩家通過控制Plants來防守Zombies的進攻,或者相反地由玩家通過控制Zombies對Plants發起進攻。
現在,我們將要考慮的問題是游戲中Zombies對Plants的進攻,請注意,本題中規則與實際游戲有所不同。游戲中有兩種角色,Plants和Zombies,每個Plant有一個攻擊位置集合,它可以對這些位置進行保護;而Zombie進攻植物的方式是走到植物所在的位置上并將其吃掉。
游戲的地圖可以抽象為一個N行M列的矩陣,行從上到下用0到N–1編號,列從左到右用0到M–1編號;在地圖的每個位置上都放有一個Plant,為簡單起見,我們把位于第r行第c列的植物記為Pr, c。
Plants分很多種,有攻擊類、防守類和經濟類等等。為了簡單的描述每個Plant,定義Score和Attack如下:
Score[Pr, c]
Zombie擊潰植物Pr, c可獲得的能源。若Score[Pr, c]為非負整數,則表示擊潰植物Pr, c可獲得能源Score[Pr, c],若為負數表示擊潰Pr, c需要付出能源 -Score[Pr, c]。
Attack[Pr, c]
植物Pr, c能夠對Zombie進行攻擊的位置集合。
Zombies必須從地圖的右側進入,且只能沿著水平方向進行移動。Zombies攻擊植物的唯一方式就是走到該植物所在的位置并將植物吃掉。因此Zombies的進攻總是從地圖的右側開始。也就是說,對于第r行的進攻,Zombies必須首先攻擊Pr, M-1;若需要對Pr, c(0≤c<M-1)攻擊,必須將Pr,M-1, Pr, M-2 … Pr, c+1先擊潰,并移動到位置(r, c)才可進行攻擊。
在本題的設定中,Plants的攻擊力是無窮大的,一旦Zombie進入某個Plant的攻擊位置,該Zombie會被瞬間消滅,而該Zombie沒有時間進行任何攻擊操作。因此,即便Zombie進入了一個Plant所在的位置,但該位置屬于其他植物的攻擊位置集合,則Zombie會被瞬間消滅而所在位置的植物則安然無恙(在我們的設定中,Plant的攻擊位置不包含自身所在位置,否則你就不可能擊潰它了)。
Zombies的目標是對Plants的陣地發起進攻并獲得最大的能源收入。每一次,你可以選擇一個可進攻的植物進行攻擊。本題的目標為,制定一套Zombies的進攻方案,選擇進攻哪些植物以及進攻的順序,從而獲得最大的能源收入。
首先把植物看成點,那么這個點有點權,且取這個點必須取它前面的點和保護它的點。
于是這就是最大權閉合子圖的模型了。
但是有一個問題,保護可能是一個環,這樣你一個點也取不了。
為此需要拓撲排序,剔除這些點。
但是還要注意,拓撲排序的邊和最大權閉合子圖的邊是反的,因為前者中雖然可能出現守護環,但是守護這個環的點可以被吃,如果不反向那么環刪不掉的同時守護環的點也會刪不掉。
(就因為這個別了半個點……)
#include<algorithm> #include<iostream> #include<cstring> #include<cctype> #include<cstdio> #include<vector> #include<queue> #include<cmath> using namespace std; typedef long long ll; const int N=705; const int M=800005; const int INF=1e9; inline int read(){int X=0,w=0;char ch=0;while(!isdigit(ch)){w|=ch=='-';ch=getchar();}while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } struct node{int nxt,to,w; }edge[M]; int head[N],cnt=-1,S,T; void add(int u,int v,int w){edge[++cnt].to=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt; } int lev[N],cur[N],dui[N]; bool bfs(int m){int r=0;for(int i=1;i<=m;i++){lev[i]=-1;cur[i]=head[i];}dui[0]=S,lev[S]=0;int u,v;for(int l=0;l<=r;l++){u=dui[l];for(int e=head[u];e!=-1;e=edge[e].nxt){v=edge[e].to;if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1;r++;dui[r]=v; if(v==T)return 1; }}}return 0; } int dinic(int u,int flow,int m){if(u==m)return flow;int res=0,delta;for(int &e=cur[u];e!=-1;e=edge[e].nxt){int v=edge[e].to;if(edge[e].w>0&&lev[u]<lev[v]){ delta=dinic(v,min(edge[e].w,flow-res),m); if(delta>0){edge[e].w-=delta;edge[e^1].w+=delta;res+=delta;if(res==flow)break; }}}if(res!=flow)lev[u]=-1;return res; } int n,m,ans,s[N],indeg[N]; queue<int>q; void Topu(){for(int i=1;i<=n*m;i++){if(!indeg[i])q.push(i);}while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i!=-1;i=edge[i].nxt){if(!(i&1))continue;int v=edge[i].to;indeg[v]--;if(!indeg[v])q.push(v);}}for(int i=1;i<=n*m;i++){if(indeg[i]){s[i]=-INF;}} } int main(){memset(head,-1,sizeof(head));n=read(),m=read();S=n*m+1,T=S+1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){int now=(i-1)*m+j;s[now]=read();int w=read();for(int k=1;k<=w;k++){int x=read()+1,y=read()+1;int bef=(x-1)*m+y;add(bef,now,INF);add(now,bef,0);indeg[bef]++;}if(j!=m){int bef=now+1;add(now,bef,INF);add(bef,now,0);indeg[now]++;}}}Topu();for(int i=1;i<=n*m;i++){if(s[i]>=0){ans+=s[i];add(S,i,s[i]);add(i,S,0);}else{add(i,T,-s[i]);add(T,i,0);}}while(bfs(T))ans-=dinic(S,INF,T);printf("%d\n",ans);return 0; }+++++++++++++++++++++++++++++++++++++++++++
?+本文作者:luyouqi233。 +
?+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
轉載于:https://www.cnblogs.com/luyouqi233/p/8460949.html
總結
以上是生活随笔為你收集整理的BZOJ1565:[NOI2009]植物大战僵尸——题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小米路由器开发版及配置-小米路由器开发版
- 下一篇: English sentences