【bzoj1565】 NOI2009—植物大战僵尸
http://www.lydsy.com/JudgeOnline/problem.php?id=1565 (题目链接)
题意
给出$n*m$的棋盘,僵尸攻击每个格子可以获得$v$的分数,每个格子又会保护一些别的格子,想攻击被保护的格子必须先攻击没被保护的格子。问获得的最大分数。
Solution
建图,被保护的点向保护它的点连边。显然,环上的点是不可能被击败的,我们Tarjan以后把环上的点以及指向环的点扔掉。剩下的点做最大权闭合子图就好了。
这里扔掉不是真的扔掉,只要不让S和T与之相连就好了。
细节
数组大小
代码
// bzoj1565 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #define LL long long #define inf (1ll<<30) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout) using namespace std; const int maxn=100010,maxm=1000010; int head[maxn],d[maxn],n,m,cnt,ans,tot,S,T; int size[maxn],dfn[maxn],low[maxn],bel[maxn],vis[maxn],val[maxn],st[maxn],DFN,scc,top; struct edge {int to,next,w;}e[maxm]; pair<int,int> E[maxm]; namespace Dinic { void link(int u,int v,int w) { e[++cnt]=(edge){v,head[u],w};head[u]=cnt; e[++cnt]=(edge){u,head[v],0};head[v]=cnt; } bool bfs() { for (int i=S;i<=T;i++) d[i]=-1; queue<int> q;q.push(S);d[S]=0; while (!q.empty()) { int x=q.front();q.pop(); for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]<0) d[e[i].to]=d[x]+1,q.push(e[i].to); } return d[T]>0; } int dfs(int x,int f) { if (x==T || f==0) return f; int w,used=0; for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]==d[x]+1) { w=dfs(e[i].to,min(e[i].w,f-used)); used+=w,e[i].w-=w;e[i^1].w+=w; if (used==f) return used; } if (!used) d[x]=-1; return used; } int main() { int flow=0; while (bfs()) flow+=dfs(S,inf); return flow; } } void link(int u,int v) {e[++cnt]=(edge){v,head[u]};head[u]=cnt;} void Tarjan(int x) { st[++top]=x;dfn[x]=low[x]=++DFN; for (int i=head[x];i;i=e[i].next) { if (!dfn[e[i].to]) { Tarjan(e[i].to); low[x]=min(low[x],low[e[i].to]); } else if (!bel[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); } if (dfn[x]==low[x]) { scc++; for (;st[top]!=x;top--) bel[st[top]]=scc,size[scc]++; bel[st[top--]]=scc;size[scc]++; } } bool dfs(int x) { if (vis[x]) return size[x]; if (size[x]>1) size[x]=0; vis[x]=1; for (int i=head[x];i;i=e[i].next) if (e[i].w) size[x]&=dfs(e[i].to); return size[x]; } int main() { scanf("%d%d",&n,&m); for (int i=0;i<n;i++) for (int x,y,t,j=1;j<=m;j++) { scanf("%d%d",&val[i*m+j],&t); for (int k=1;k<=t;k++) scanf("%d%d",&x,&y),link(x*m+y+1,i*m+j); if (j<m) link(i*m+j,i*m+j+1); } for (int i=1;i<=n*m;i++) if (!dfn[i]) Tarjan(i); for (int i=1;i<=n*m;i++) for (int j=head[i];j;j=e[j].next) if (bel[i]!=bel[e[j].to]) E[++tot]=pair<int,int>(bel[i],bel[e[j].to]); memset(head,0,sizeof(head));cnt=1; for (int i=1;i<=tot;i++) Dinic::link(E[i].first,E[i].second,inf); for (int i=1;i<=scc;i++) if (!vis[i]) dfs(i); S=0,T=n*m+1; for (int i=1;i<=n*m;i++) if (size[bel[i]]) { if (val[i]>=0) Dinic::link(S,bel[i],val[i]),ans+=val[i]; else Dinic::link(bel[i],T,-val[i]); } ans=max(0,ans-Dinic::main()); printf("%d",ans); return 0; }
This passage is made by MashiroSky.