1. 程式人生 > >[bzoj1565]植物大戰僵屍

[bzoj1565]植物大戰僵屍

image fine data while true using fin 保護 它的

技術分享圖片 Input 技術分享圖片 Output 僅包含一個整數,表示可以獲得的最大能源收入。註意,你也可以選擇不進行任何攻擊,這樣能源收入為0。 Sample Input 3 2 10 0 20 0 -10 0 -5 1 0 0 100 1 2 1 100 0

Sample Output

25

Hint

在樣例中, 植物P1,1可以攻擊位置(0,0), P2, 0可以攻擊位置(2,1)。
一個方案為,首先進攻P1,1, P0,1,此時可以攻擊P0,0 。共得到能源收益為(-5)+20+10 = 25。註意, 位置(2,1)被植物P2,0保護,所以無法攻擊第2行中的任何植物。
【大致數據規模】
約20%的數據滿足1 ≤ N, M ≤ 5;
約40%的數據滿足1 ≤ N, M ≤ 10;
約100%的數據滿足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

最大權閉合子圖問題。

此類問題為:有n個點,每個點有一個權值(可以為負數),選某個點就要先選其它的一些點。求最大收益。

此類問題的一般性解法為:

1.用拓撲排序把永遠選不了的點刪掉。

2.若第i個點需要先選第j個點,則連一條(i,j,inf)的邊。

3.如果該點點權為正,則連一條(S,i,val)的邊。

4.否則連一條(i,T,-val)的邊

5.最後答案為所有正權點的權值總和-最大流。

具體參見:https://www.2cto.com/kf/201611/563122.html

對於此題,顯然,對於每個點,它能防禦到的 每一行的最前面的點 的後面的點 都是要先選這個點的。

即設綠點能防禦到所有黃點,那麽要選所有紅色區域就要先選綠點。技術分享圖片

然後就做完了。

#include<iostream>
#include<cstring>
#include<cstdio>
#define no(r,c) r*m+c+1
#define inf 2e9+7
using namespace std;
int front[50];bool used[2000];
int into[2000],que[2000000],HH=0,TT=0;
int h[500000],nxt[1000000],to[1000000],cap[1000000],TOT=0;
int mp[50][50],x[500000],y[500000];
int S,T,level[2000],iter[2000];
void ins(int u,int
v){nxt[++TOT]=h[u];h[u]=TOT;to[TOT]=v;} void ins2(int u,int v,int c){nxt[++TOT]=h[u];h[u]=TOT;to[TOT]=v;cap[TOT]=c;nxt[++TOT]=h[v];h[v]=TOT;to[TOT]=u;cap[TOT]=0;} bool bfs() { memset(level,0,sizeof(level)); int HH=0,TT=0; que[TT++]=S;level[S]=1; while(HH<TT) { int u=que[HH++]; for(int i=h[u];i;i=nxt[i]) { int v=to[i]; if(cap[i]&&!level[v]){level[v]=level[u]+1;que[TT++]=v;} } } return level[T]?true:false; } int dfs(int u,int f) { if(u==T)return f; int used=0; for(int &i=iter[u];i;i=nxt[i]) { int v=to[i];if(!cap[i]||level[v]!=level[u]+1)continue; int w=dfs(v,min(cap[i],f-used)); if(w) { cap[i]-=w;cap[i^1]+=w; used+=w;if(used==f)return f; } } return used; } int dinic() { int flow=0; while(bfs()){for(int i=1;i<=2000;i++)iter[i]=h[i];flow+=dfs(S,inf);} return flow; } int main() { int n,m,tot=0;scanf("%d%d",&n,&m);S=n*m+1,T=n*m+2; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { int w;scanf("%d%d",&mp[i][j],&w); memset(front,-1,sizeof(front)); for(int k=1;k<=w;k++) { int r,c;scanf("%d%d",&r,&c); front[r]=max(front[r],c); } front[i]=max(front[i],j-1); for(int r=0;r<n;r++) for(int c=0;c<=front[r];c++){x[++tot]=no(i,j);y[tot]=no(r,c);ins(no(i,j),no(r,c));into[no(r,c)]++;} } for(int i=1;i<=n*m;i++)if(!into[i])que[TT++]=i; while(HH<=TT){int u=que[HH++];used[u]=1;for(int i=h[u];i;i=nxt[i])if(!(--into[to[i]]))que[TT++]=to[i];} memset(h,0,sizeof(h));memset(nxt,0,sizeof(nxt));memset(to,0,sizeof(to));TOT=1; int sum=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(used[no(i,j)]) if(mp[i][j]>0)ins2(S,no(i,j),mp[i][j]),sum+=mp[i][j]; else ins2(no(i,j),T,-mp[i][j]); for(int i=1;i<=tot;i++)if(used[x[i]]&&used[y[i]])ins2(y[i],x[i],inf); printf("%d",sum-dinic()); return 0; }

[bzoj1565]植物大戰僵屍