BZOJ1565 NOI2009 植物大战僵尸 拓扑排序+网络流
题意:N*M的网格中有K个植物,每个植物可以保护一些格点,如果该植物没被吃掉,则被保护的格点不可到达,每个僵尸只能从最右边进入,从右往左吃,每个植物有一定价值,求一个吃植物的顺序使得被吃植物价值和最大。
题解:
最大权闭合子图+拓扑排序的说……
首先根据保护关系建边,由保护指向被保护,保护关系有两种:
直接保护:就是输入里给定的
间接保护:每个植物能保护其左侧的所有植物
由于可能存在环,环上的植物都是无敌的而且被环上植物所保护的植物一定也是无敌的(PVZ里真有这种情况那还玩个毛啊QAQ)。
然后拓扑排序判定每个植物是否在环上或者被环上植物保护。
然后建网络流,条件就是一个植物的入度是否为0,是则入图,s连正权,负权连t,然后就全是套路了……
#include <queue> #include <vector> #include <cstdio> #include <climits> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=3000+2; struct HASH{ int u; HASH *next; HASH(){} HASH(int _u,HASH *_next):u(_u),next(_next){} }*table[MAXN],mem[MAXN*MAXN]; struct EDGE{ int u,c; EDGE(){} EDGE(int _u,int _c):u(_u),c(_c){} }e[MAXN*MAXN]; int R,C,N,cnt,c[MAXN],g[MAXN][MAXN],sum,d[MAXN],cur[MAXN]; queue<int> q; vector<int> tab[MAXN]; void Insert1(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u])),d[v]++;} void Insert2(int u,int v,int c){ tab[u].push_back(cnt),e[cnt++]=EDGE(v,c); tab[v].push_back(cnt),e[cnt++]=EDGE(u,0); } void Topological_Sort(){ for(int i=1;i<=N;i++) if(!d[i]) q.push(i); int x; while(!q.empty()){ x=q.front(),q.pop(); for(HASH *p=table[x];p;p=p->next){ d[p->u]--; if(!d[p->u]) q.push(p->u); } } } bool BFS(int s,int t){ memset(d,-1,sizeof(d)); d[s]=0,q.push(s); int x; while(!q.empty()){ x=q.front(),q.pop(); for(int i=0;i<tab[x].size();i++) if(d[e[tab[x][i]].u]==-1 && e[tab[x][i]].c) d[e[tab[x][i]].u]=d[x]+1,q.push(e[tab[x][i]].u); } return d[t]>0; } int DFS(int x,int f,int t){ if(x==t) return f; int flow,used=0; for(int i=cur[x];i<tab[x].size();i++) if(e[tab[x][i]].c && d[e[tab[x][i]].u]==d[x]+1){ flow=DFS(e[tab[x][i]].u,min(f-used,e[tab[x][i]].c),t); e[tab[x][i]].c-=flow,e[tab[x][i]^1].c+=flow,used+=flow; if(e[tab[x][i]].c) cur[x]=i; if(f==used) return f; } if(!used) d[x]=-1; return used; } int Dinic(int s,int t){ int ret=0; while(BFS(s,t)){ memset(cur,0,sizeof(cur)); ret+=DFS(s,INT_MAX,t); } return ret; } int main(){ cin >> R >> C; for(int i=1,w;i<=R;i++) for(int j=1;j<=C;j++){ if(!g[i][j]) g[i][j]=++N; cin >> c[g[i][j]] >> w; for(int k=1,a,b;k<=w;k++){ cin >> a >> b,a++,b++; if(!g[a][b]) g[a][b]=++N; Insert1(g[i][j],g[a][b]); } } for(int i=1;i<=R;i++) for(int j=2;j<=C;j++) for(int k=1;k<j;k++) Insert1(g[i][j],g[i][k]); Topological_Sort(); cnt=0; for(int i=1;i<=N;i++){ if(d[i]) continue; if(c[i]<0) Insert2(0,i,-c[i]); else Insert2(i,N+1,c[i]),sum+=c[i]; for(HASH *p=table[i];p;p=p->next) if(!d[p->u]) Insert2(i,p->u,INT_MAX); } printf("%d\n",sum-Dinic(0,N+1)); return 0; }