bzoj1565
1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2916 Solved: 1330
[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 。
一道比较裸的最大权闭合子图问题吧。重点是处理环!!
如果a保护b,那么选了b必选a,对应到最大权闭合子图里,就是b->a建边。
最大权闭合子图问题具体看blog
https://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html
此题有环,考虑到成环的植物是不可能被啃食的,所以去掉环中的点,建立新图。处理环可以用topsort。
注意topsort的时候还是按照 a保护b a->b来建边
最后跑maxflow才改成b->a
原因:一个有向图所有边反向,有可能原图的环会改变
那么例子是ZJ给出的:
然后这个题就被gay了
/* 注意topsort的时候还是按照 a保护b a->b来建边 最后跑maxflow才改成b->a 原因:一个有向图所有边反向,有可能原图的环会改变 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> #define inf 0x3f3f3f3f #define ll long long #define N 605 using namespace std; int n,m,sum,tot,S,T,sc[N],in[N],ok[N],cur[N],hd[N],vis[N],d[N]; struct edge{int v,next,cap;}e[N*N*2]; vector<int>g[N];queue<int>q; void adde(int u,int v,int c){ e[tot].v=v; e[tot].next=hd[u]; e[tot].cap=c; hd[u]=tot++; } void topsort(){ for(int i=1;i<T;i++){ if(!in[i]) ok[i]=1,q.push(i); } while(!q.empty()){ int u=q.front();q.pop(); for(int i=0;i<g[u].size();i++){ int v=g[u][i];--in[v]; if(!in[v]){ ok[v]=1; q.push(v); } } } } bool bfs(){ memset(vis,0,sizeof(vis)); d[S]=0;vis[S]=1;q.push(S); while(!q.empty()){ int u=q.front();q.pop(); for(int i=hd[u];~i;i=e[i].next){ int v=e[i].v; if(e[i].cap&&!vis[v]){ vis[v]=1; d[v]=d[u]+1; q.push(v); } } } return vis[T]; } int dfs(int u,int a){ if(u==T||!a)return a; int fl=0,f; for(int &i=cur[u];~i;i=e[i].next){ int v=e[i].v; if(e[i].cap&&d[v]==d[u]+1&&(f=dfs(v,min(e[i].cap,a)))){ fl+=f;a-=f;e[i].cap-=f; e[i^1].cap+=f;if(!a)break; } } return fl; } int main(){ #ifdef wsy freopen("data.in","r",stdin); #else //freopen(".in","r",stdin); //freopen(".out","w",stdout); #endif memset(hd,-1,sizeof(hd)); scanf("%d%d",&n,&m);S=0;T=n*m+1; for(int i=1;i<T;i++){ int c,x,y,id; scanf("%d%d",&sc[i],&c); for(int j=1;j<=c;j++){ scanf("%d%d",&x,&y); x++;y++; id=(x-1)*m+y; g[i].push_back(id); in[id]++; // printf("%d %d\n",i,id); } if(i%m)g[i+1].push_back(i),in[i]++/*,printf("%d %d\n",i+1,i)*/; } topsort(); for(int i=1;i<T;i++){ if(!ok[i])continue; for(int j=0;j<g[i].size();j++){ int v=g[i][j]; if(!ok[v])continue; adde(v,i,inf);adde(i,v,0); // printf("%d %d %d\n",i,v,inf); } } for(int i=1;i<T;i++){ if(sc[i]>0&&ok[i])sum+=sc[i]; if(sc[i]>0&&ok[i])adde(S,i,sc[i]),adde(i,S,0)/*,printf("%d %d %d\n",S,i,sc[i])*/; if(sc[i]<0&&ok[i])adde(i,T,-sc[i]),adde(T,i,0)/*,printf("%d %d %d\n",i,T,-sc[i])*/; } int flow=0; while(bfs()){ for(int i=S;i<=T;i++)cur[i]=hd[i]; flow+=dfs(S,inf); } printf("%d",sum-flow); return 0; }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。