1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2922 Solved: 1332
[Submit][Status][Discuss]
Description
Input
Output
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。
Sample Input
3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
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 。
Source
这道题是对最大闭合子图的应用
环上的点肯定是不能吃的,我们用topsort进行去环,求出答案即可
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <algorithm> using namespace std; inline int read() { int x=0;int f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } struct node { int y; int next; int back; int flow; }e[200100],ee[200100]; int linkk[200010]; int linkkk[200000]; int id[100010]; int f[100010]; int summ=0; int q[100101]; int flag[100010]={}; int n,m,head,tail,len,st,end; int getpoint(int x,int y) { return x*m-m+y; } void insert1(int xx,int yy) { ee[++len].y=yy; ee[len].next=linkkk[xx]; linkkk[xx]=len; ee[len].flow=4728479; } void insert(int xx,int yy,int vv) { e[++len].y=yy; e[len].flow=vv; e[len].next=linkk[xx]; e[len].back=len+1; linkk[xx]=len; e[++len].y=xx; e[len].next=linkk[yy]; e[len].flow=0; e[len].back=len-1; linkk[yy]=len; } void topsort()//去环 { tail=0; head=0; for(int i=1;i<=n*m;i++) { if(!id[i]) q[++tail]=i,flag[i]=1; } while(head<tail) { int tn=q[++head]; for(int i=linkkk[tn];i;i=ee[i].next) { id[ee[i].y]--; if(!id[ee[i].y]) { q[++tail]=ee[i].y; flag[ee[i].y]=1; } } } } void buildtu() { len=0; for(int i=1;i<=n*m;i++) { if(flag[i]==0) continue; if(f[i]>0) insert(st,i,f[i]),summ+=f[i]; if(f[i]<0) insert(i,end,-f[i]); for(int j=linkkk[i];j;j=ee[j].next) { if(flag[ee[j].y]==0) continue; insert(ee[j].y,i,624726488); } } } int level[10100]; bool vis[10010]; int getlevel() { memset(level,-1,sizeof(level)); memset(q,0,sizeof(q)); tail=head=0; level[st]=0; q[++tail]=st; while(head<tail) { int tn=q[++head]; for(int i=linkk[tn];i;i=e[i].next) { if(level[e[i].y]==-1&&e[i].flow!=0) { q[++tail]=e[i].y; level[e[i].y]=level[tn]+1; } } } return level[end]>-1; } int getmaxflow(int stt,int flow) { int maxflow=0; int d=0; if(stt==end) return flow; for(int i=linkk[stt];i&&maxflow<flow;i=e[i].next) { if(level[e[i].y]==level[stt]+1&&e[i].flow) { if(d=getmaxflow(e[i].y,min(flow-maxflow,e[i].flow))) { maxflow+=d; e[i].flow-=d; e[e[i].back].flow+=d; } } } if(!maxflow) level[stt]=-1; return maxflow; } void dinic() { int ans=0; int sum; while(getlevel()) { while(sum=getmaxflow(st,31763786)) ans+=sum; } cout<<summ-ans<<endl; } int main() { cin>>n>>m; st=0; end=n*m+1; for(int i=1;i<=n*m;i++) { f[i]=read(); int w; cin>>w; int now; int a,b; while(w--) { a=read()+1; b=read()+1; now=getpoint(a,b); insert1(i,now); id[now]++; } if(i%m==0) continue; insert1(i+1,i);id[i]++; } topsort(); buildtu(); dinic(); return 0; }