【bzoj1565】[NOI2009]植物大战僵尸 拓扑排序+最大权闭合图

原文地址:http://www.cnblogs.com/GXZlegend/p/6808268.html



题目描述

输入

输出

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

样例输入

3 2

10 0

20 0

-10 0

-5 1 0 0

100 1 2 1

100 0

样例输出

25



题解

拓扑排序+最大权闭合图

一个坑点卡了半年。。

由题目描述易知如果某些植物保护关系成了环,那它们都不能吃掉。所以若A能保护B,则A向B连边,再用拓扑排序判环(Tarjan也可以)。

注意如果A在B的前边,那么也应看作A保护B。

然后所有被无敌植物保护的植物都不能吃掉,应用dfs判掉。

最后跑最大权闭合图即可。

坑点有点多,实际没啥太难的。

#include <cstdio>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
queue<int> q;
int n , m , map[610][610] , w[610] , rd[610] , flag[610];
int head[610] , to[400000] , val[400000] , next[400000] , cnt = 1 , s , t , dis[610];
void init()
{
    int i , j;
    for(i = 1 ; i <= n * m ; i ++ )
        for(j = 1 ; j <= n * m ; j ++ )
            if(map[i][j])
                rd[j] ++ ;
    for(i = 1 ; i <= n * m ; i ++ )
        if(!rd[i])
            q.push(i);
    while(!q.empty())
    {
        i = q.front() , q.pop() , flag[i] = 1;
        for(j = 1 ; j <= n * m ; j ++ )
        {
            if(map[i][j])
            {
                rd[j] -- ;
                if(!rd[j]) q.push(j);
            }
        }
    }
}
void add(int x , int y , int z)
{
    to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
    int x , i;
    while(!q.empty()) q.pop();
    memset(dis , 0 , sizeof(dis));
    dis[s] = 1 , q.push(s);
    while(!q.empty())
    {
        x = q.front() , q.pop();
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] && !dis[to[i]])
            {
                dis[to[i]] = dis[x] + 1;
                if(to[i] == t) return 1;
                q.push(to[i]);
            }
        }
    }
    return 0;
}
int dinic(int x , int low)
{
    if(x == t) return low;
    int temp = low , i , k;
    for(i = head[x] ; i ; i = next[i])
    {
        if(val[i] && dis[to[i]] == dis[x] + 1)
        {
            k = dinic(to[i] , min(temp , val[i]));
            if(!k) dis[to[i]] = 0;
            val[i] -= k , val[i ^ 1] += k;
            if(!(temp -= k)) break;
        }
    }
    return low - temp;
}
void dfs(int x)
{
	int i;
	for(i = 1 ; i <= n * m ; i ++ )
		if(map[x][i] && flag[i])
			flag[i] = 0 , dfs(i);
}
int main()
{
    int i , j , k , x , y , ans = 0;
    scanf("%d%d" , &n , &m);
    s = 0 , t = n * m + 1;
    for(i = 1 ; i <= n ; i ++ )
    {
        for(j = 1 ; j <= m ; j ++ )
        {
            scanf("%d%d" , &w[(i - 1) * m + j] , &k);
            if(j > 1) map[(i - 1) * m + j][(i - 1) * m + j - 1] = 1;
            while(k -- ) scanf("%d%d" , &x , &y) , map[(i - 1) * m + j][x * m + y + 1] = 1;
        }
    }
    init();
    for(i = 1 ; i <= n * m ; i ++ )
    	if(!flag[i])
    		dfs(i);
    for(i = 1 ; i <= n * m ; i ++ )
    {
        if(flag[i])
        {
            if(w[i] >= 0) add(s , i , w[i]) , ans += w[i];
            else add(i , t , -w[i]);
            for(j = 1 ; j <= n * m ; j ++ )
                if(map[j][i] && flag[j])
                    add(i , j , inf);
        }
    }
    while(bfs()) ans -= dinic(s , inf);
    printf("%d\n" , ans);
    return 0;
}
时间: 2024-11-01 19:59:49

【bzoj1565】[NOI2009]植物大战僵尸 拓扑排序+最大权闭合图的相关文章

BZOJ 1565 植物大战僵尸(拓扑排序+最大权闭合子图)

图中的保护关系就类似于最大权闭合子图.即你想杀x,你就一定要杀掉保护x的点,那么把x向保护它的点连边.那么题目就转化成了最大权闭合子图的问题. 但是这个图有点特殊啊... 考虑有环的情况,显然这个环以及指向这个环的点都不能选. 所以还要把这个图的反图进行一遍拓扑排序,这样忽略掉了这些点了... # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # i

【BZOJ-1565】植物大战僵尸 拓扑排序 + 最小割

1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1972  Solved: 917[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 Sample

b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子图

b2OJ_1565_[NOI2009]植物大战僵尸_拓扑排序+最大权闭合子 题意:n*m个植物,每个植物有分数(可正可负),和能保护植物的位置.只能从右往左吃,并且不能吃正被保护着的,可以一个不吃,求获得的最大分数. 分析:把每个植物向能保护它的植物连边.源点连正权点,负权点连汇点. 考虑在一个环上的植物是吃不到的,我们可以用拓扑排序确定哪些是能吃的. 然后求一遍最大权闭合子图就是答案. 代码: 1 #include <stdio.h> 2 #include <string.h>

[bzoj1565][NOI2009]植物大战僵尸_网络流_拓扑排序

植物大战僵尸 bzoj1565 题目大意:给你一张网格图,上面种着一些植物.你从网格的最右侧开始进攻.每个植物可以对僵尸提供能量或者消耗僵尸的能量.每个植物可以保护一个特定网格内的植物,如果一个植物被保护,那么如果僵尸想吃掉该植物就必须先吃掉保护它的植物.问:僵尸最多能获得多少能量. 注释:1<=N(网格的宽)<=20,1<=M(网格的长)<=30,-20,000<=代价和收益<=20,000. 想法:前置题目([NOI2006]最大获利).这道题和最大获利比较相像,如

BZOJ 1565 NOI2009 植物大战僵尸 最大权闭合图+拓扑排序

题目大意:给定一个m*n的草坪,每块草坪上的植物有两个属性: 1.啃掉这个植物,获得收益x(可正可负) 2.保护(r,c)点的植物不被啃掉 任何一个点的植物存活时,它左侧的所有植物都无法被攻击 求最大收益 首先这个保护和被保护的关系就是最大权闭合图的连边关系 然后直接跑就行 然后我们就会发现没过样例0.0 原因当图出现环时,根据题意,环上的所有点都不能取(想象一个无冷却的食人花前面放一个坚果) 所以这题还要去掉环 由于环上的点不能取,所以所有指向环上的点的点都不能取 这个条件看起来不太好做,我们

BZOJ 1565 植物大战僵尸(最大权闭合图)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1565 题意:植物大战僵尸,一个n*m的格子,每 个格子里有一个植物,每个植物有两个属性:(1)价值:(2)保护集合,也就是这个植物可以保护矩阵中的某些格子.现在你是僵尸,你每次只能从(i,m) 格子进入,从右向左进攻.若一个格子是被保护的那么你是不能进入的.每进入一个格子则吃掉该格子的植物并得到其价值(价值有可能是负的).注意,每次在进 入一行后还可以再退到最右侧然后再换一行吃别的.问

tyvj P1135 - 植物大战僵尸 最大权闭合图

P1135 - 植物大战僵尸 From ytt    Normal (OI)总时限:10s    内存限制:128MB    代码长度限制:64KB 背景 Background 虽然这么多天了,,虽然寂寞的玩了好多遍植物大战僵尸,,还是觉得写题目比控制脑残僵尸比较好玩` 描述 Description 植物大战僵尸    [问题描述]Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombi

1565: [NOI2009]植物大战僵尸 - BZOJ

Description Input Output仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0.Sample Input3 210 020 0-10 0-5 1 0 0100 1 2 1100 0Sample Output25HINT 在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1).一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 .共得到能源收益为(-5)+20+10 = 25.注意, 位置(2,

HDU 3061:Battle(最大权闭合图)

http://acm.hdu.edu.cn/showproblem.php?pid=3061 题意:中文题意. 思路:和上一题神似啊,比上一题还简单,重新看了遍论文让我对这个理解更加深了. 闭合图:如果某个点在图中的话,那么这个点的后继点全部都要在图中. 对应至题目,这里的必须攻占b以后才能攻占a,那么是a依赖于b.如果a在图中的话,那么b必定在图中(因为a是依赖于b的),所以是a连向b(而不是b连向a). 这里总结一下做最大权闭合图的套路:把权值为正的点与超级源点S相连,容量为该权值,把权值为