1. 程式人生 > >NOI2009 植物大戰殭屍

NOI2009 植物大戰殭屍

題目描述

題解:

由於幹每棵植物之前需要先幹掉它右面的植物和保護他的植物,

我們可以發現這是最大權閉合子圖問題。

 

簡單提一下。

閉合子圖,指這個子圖中所有的點只會指向子圖中的點。

最大權,指這些點有點權,要求得到的閉合子圖點權之和最大。

解決辦法是,$S$向正點權的點連容量為點權的邊,負點權的點向$T$連容量為點權相反數的邊。

然後正點權之和-得到的最大流即為最大權。

 

然而這道題還有種情況,就是自己守自己。

這種情況會構成環,所以拓撲/$Tarjan$除環。

程式碼:

#include<queue>
#include<vector>
#include
<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 650 #define ll long long const int inf = 0x3f3f3f3f; const ll Inf = 0x3f3f3f3f3f3f3f3fll; inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,hed[N],cnt=-1,S=0,T=601,v[N],ind[N]; vector<int>ve[N]; int _id(int x,int y) { return x*m+y+1; } struct EG { int to,nxt; ll w; }e[N*N*10]; void ae(int f,int t,ll w) { e[++cnt].to = t; e[cnt].nxt
= hed[f]; e[cnt].w = w; hed[f] = cnt; } void AE(int f,int t,ll w) { ae(f,t,w); ae(t,f,0); } queue<int>q; bool vis[N]; ll sum; int dep[N],cur[N]; bool bfs() { memset(dep,0x3f,sizeof(dep)); memcpy(cur,hed,sizeof(cur)); dep[S]=0,vis[S]=1;q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].to; if(e[j].w&&dep[to]>dep[u]+1) { dep[to] = dep[u]+1; if(!vis[to]) { vis[to] = 1; q.push(to); } } } vis[u] = 0; } return dep[T]!=inf; } ll dfs(int u,ll lim) { if(u==T||!lim)return lim; ll fl=0,f; for(int j=cur[u];~j;j=e[j].nxt) { cur[u] = j; int to = e[j].to; if(dep[to]==dep[u]+1&&(f=dfs(to,min(lim,e[j].w)))) { fl+=f,lim-=f; e[j].w-=f,e[j^1].w+=f; if(!lim)break; } } return fl; } ll dinic() { ll ret = 0; while(bfs())ret+=dfs(S,Inf); return ret; } int main() { n = rd(),m = rd(); memset(hed,-1,sizeof(hed)); for(int i=0;i<n;i++) for(int s,x,y,j=0;j<m;j++) { int u = _id(i,j); v[u] = rd(); s = rd(); while(s--) { x = rd(),y = rd(); int to = _id(x,y); ind[to]++; ve[u].push_back(to); } if(j!=0) { ind[u-1]++; ve[u].push_back(u-1); } } for(int i=m;i<=n*m;i+=m) if(!ind[i])q.push(i); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 1; if(v[u]>0)sum+=v[u]; for(int i=0;i<ve[u].size();i++) { int to = ve[u][i]; ind[to]--; if(!ind[to]) q.push(to); } } for(int i=1;i<=n*m;i++) { if(vis[i]) { if(v[i]>0)AE(S,i,v[i]); if(v[i]<0)AE(i,T,-v[i]); for(int j=0;j<ve[i].size();j++) { int to = ve[i][j]; if(vis[to])AE(to,i,Inf); } } } memset(vis,0,sizeof(vis)); printf("%lld\n",sum-dinic()); return 0; }