Bzoj1565 [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2363  Solved: 1092

Description

Input

Output

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

Sample Input

3 2
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

网络流+拓扑排序

因为植物可能会互相保护而形成环,所以先用拓扑排序排除环,求出图中的闭合子图。

然后按照先吃右边才能吃左边的关系,从每个点向它左边一格的点连边,容量为INF

保护型的植物向它保护的植物连边,容量为INF。

吃植物能获得收益时,该植物向汇点连边,容量为收益。

吃植物需要代价时,源点向该植物连边,容量为代价的绝对值。

答案=可能获得的收益总和-最小割。

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #include<queue>
  9 using namespace std;
 10 const int mx[5]={0,1,0,-1,0};
 11 const int my[5]={0,0,1,0,-1};
 12 const int INF=1e9;
 13 const int mxn=2010;
 14 int read(){
 15     int x=0,f=1;char ch=getchar();
 16     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 17     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 18     return x*f;
 19 }
 20 struct edge{
 21     int v,nxt,f;
 22 }e[mxn*500];
 23 int hd[mxn],mct=1;
 24 void add_edge(int u,int v,int f){
 25     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].f=f;hd[u]=mct;return;
 26 }
 27 void insert(int u,int v,int f){
 28     add_edge(u,v,f);add_edge(v,u,0);return;
 29 }
 30 vector<int>eg[mxn];
 31 int n,m,S,T;
 32 int d[mxn];
 33 bool BFS(){
 34     memset(d,0,sizeof d);
 35     queue<int>q;
 36     d[S]=1;
 37     q.push(S);
 38     while(!q.empty()){
 39         int u=q.front();q.pop();
 40         for(int i=hd[u];i;i=e[i].nxt){
 41             int v=e[i].v;
 42             if(e[i].f && !d[v]){
 43                 d[v]=d[u]+1;
 44                 q.push(v);
 45             }
 46         }
 47     }
 48     return d[T];
 49 }
 50 int DFS(int u,int lim){
 51     if(u==T)return lim;
 52     int f=0,tmp;
 53     for(int i=hd[u];i;i=e[i].nxt){
 54         int v=e[i].v;
 55         if(d[v]==d[u]+1 && e[i].f && (tmp=DFS(v,min(lim,e[i].f)))){
 56             e[i].f-=tmp;   e[i^1].f+=tmp;
 57             f+=tmp;        lim-=tmp;
 58             if(!lim)return f;
 59         }
 60     }
 61     d[u]=0;
 62     return f;
 63 }
 64 int Dinic(){
 65     int res=0;
 66     while(BFS())res+=DFS(S,INF);
 67     return res;
 68 }
 69 int id[50][50],cnt=0,ed;
 70 void init(){
 71     for(int i=1;i<=n;i++)
 72      for(int j=1;j<=m;j++)
 73          id[i][j]=++cnt;
 74     ed=n*m;
 75     return;
 76 }
 77 int sc[mxn];
 78 int ind[mxn];
 79 int st[mxn],top=0;
 80 bool vis[mxn];
 81 void topo(){//拓扑排序,判断植物能否攻击
 82     int i,j,res=0;
 83     for(i=1;i<=cnt;i++)
 84         if(!ind[i])st[++top]=i;
 85     while(top){
 86         int u=st[top--];
 87         vis[u]=1;
 88         if(sc[u]>0){
 89             res+=sc[u];
 90             insert(u,T,sc[u]);//可能得到的分数
 91         }
 92         else  insert(S,u,-sc[u]);//需要付出的代价
 93         for(j=0;j<eg[u].size();j++){
 94             int v=eg[u][j];
 95             ind[v]--;
 96             insert(u,v,INF);
 97             if(!ind[v])st[++top]=v;
 98         }
 99     }
100     for(i=1;i<=n;i++)
101         for(j=2;j<=m;j++){
102             if(vis[id[i][j]] && vis[id[i][j-1]]){//先吃右面再吃左面
103                 insert(id[i][j],id[i][j-1],INF);
104             }
105         }
106     res=res-Dinic();
107     printf("%d\n",res);
108 }
109 int main(){
110     int i,j,w,x,y;
111     n=read();m=read();
112     init();
113     S=0;T=ed+1;
114     for(i=1;i<=n;i++){
115         for(j=1;j<=m;j++){
116             sc[id[i][j]]=read();
117             w=read();
118             while(w--){
119                 x=read()+1;y=read()+1;
120                 eg[id[i][j]].push_back(id[x][y]);
121                 ind[id[x][y]]++;
122             }
123             if(j>1){//先解锁右面的才能吃左面的
124                 eg[id[i][j]].push_back(id[i][j-1]);
125                 ind[id[i][j-1]]++;
126             }
127         }
128     }
129     topo();
130     return 0;
131 }
时间: 2024-10-15 14:00:40

Bzoj1565 [NOI2009]植物大战僵尸的相关文章

NOI2009植物大战僵尸

这题应该分两步来做: 1.拓扑排序,去掉无敌点 2.求最大闭合子图 需要注意几点: 1.拓扑排序时,如果(i,j)可以攻击到(x,y),那么增加(x,y)的入度,而不是(i,j)的入度 因为入度代表着要攻击它需要事先攻击几个点 2.求最大闭合子图时,用所有的正权点-最大流 3.求最大闭合子图时,如果(i,j)可以攻击到(x,y),那么连一条边(x,y)到(i,j),容量为正无穷 因为在最大闭合子图中边(x,y)到(i,j)意味着选(x,y)就必须要选(i,j),这与实际含义相符 4.s到正权点,

COGS410. [NOI2009] 植物大战僵尸

410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多种不同的挑战系列,比如Protect Your Brain.Bowling等等.其中最为经典的,莫过于玩家通过控制Plants来

图论(网络流):COGS 410. [NOI2009] 植物大战僵尸

410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多种不同的挑战系列,比如Protect Your Brain.Bowling等等.其中最为经典的,莫过于玩家通过控制Plants来

bzoj 1565 [NOI2009]植物大战僵尸

拓扑排序+最小割. 每个植物有它保护的一些植物,等价于选一些点的先决条件是其它一些点,最大权闭合子图问题. 发现图里有环,所以环里的点都不能选,先决条件是环里的点的点也不能选,所以把所有边反向拓扑排序,拓扑不到的点不能选. 无视掉不能选的点后裸最大权闭合子图建图就好了. 一个最大权闭合子图裸题的题解 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm>

【BZOJ1565】 植物大战僵尸

Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 -10 0 -5 1 0 0 100 1 2 1 100 0 Sample Output 25 Solution 按照依赖关系建立有向图:若清除$a$前必须清除$b$,则连边$a$至$b$.这些依赖关系包括同行植物左边对右边的依赖,以及被保护者对保护者的依赖. 首先不能考虑开挂集团,也就是依赖关系

luogu2805 [NOI2009]植物大战僵尸

想象一下,要搞掉一个植物,必须先搞掉另一些植物--我们可以发现这是一个最大权闭合子图的问题. 最大权闭合子图的话,太空飞行计划问题是一个入门题,可以一看. 然而我们手玩一下样例就会惊恐地发现,保护关系出现了环. 比如说: 从 i 到 j 的箭头是说要搞 i 就要先搞 j,这是为了和最大权闭合子图的模型对应. 要搞 3 就要先搞 4,要搞 4 就要先搞 5,要搞 5 就要先搞 3--简直是乱来-- 这就像是一个无冷却食人花前面放一个坚果 所以就要删环了,把边倒过来拓扑排序一下,能被拓扑到的点就是合

NOI2009 植物大战僵尸

啊一道好题感觉写得挺爽的啊这题这种有一点懵逼然后学了一点东西之后很明朗的感觉真是好!预处理参考 :http://www.cppblog.com/MatoNo1/archive/2014/11/01/142798.html?opt=admin建图参考 :http://hihocoder.com/problemset/problem/1398?sid=1010444 #include<iostream> #include<cstdio> #include<cstdlib>

[Luogu 2805]NOI2009 植物大战僵尸

<题目链接> 这题是个比较经典的最大权闭合子图,可以建图转化为最小割问题,再根据最大流最小割定理,采用任意一种最大流算法求得. 对于每个点,如果点权w为正,则从源点到这个点连一条边权为w的有向边:否则如果w为负则从这个点到汇点连一条有向边.加边的时候预处理出反图的每个点入度. 其次,每一个被保护的点到保护它的点连一条边权为INF的有向边. 注意同一行的左侧点受到右侧点的间接保护,因此对于每一个不位于当前行最右的点,都要向其右侧的一个点连一条INF有向边(连一条即可,不必连所有). 初始化完成后

98植物大战僵尸OL_僵尸迷阵

最近在玩植物大战僵尸Ol打到僵尸迷阵,打了个700分倒数第一,擦.....俗话说的好,失败是成功的妈妈,于是花了点时间写了一个小玩意,我相信下次我一定能拿第一 代码非常简单: using UnityEngine; using System.Collections; using UnityEngine.UI; public class MyScript : MonoBehaviour { // Use this for initialization void Start () { } // Upd