题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3527

题目大意:一有向图图n个点,n条边,每个点有且只有一条出边。取某个点会有信仰值,同时某个点与它的后继结点同时取的话, 它的信仰值会改变一个值,问怎么取点,使得总信仰值最大

解题思路:拓扑排序+树形DP.这一题的图很有特色,我第一次碰到,官方题解说着实章鱼图,因为每个点只有一条出边,那么要么肯定存在一个或多个环,其他的点依靠着这些环。这题攒了一天才AC,原因是一个int64写成了int,悲催啊...

对于本题,我的解法是先处理章鱼的触须,也就是那些依靠环的边,然后再处理一个个的环。前者就是普通的树形dp,因为每个点只有建或不建两种状态,设dp[i][0]表示i点不建尼姑院获得的最大信仰值,dp[i][1]表示i点建尼姑院获得的最大信仰值,那么触须部分就可以用dp[next][0] = max(dp[i][0],dp[i][1]),dp[next][1] = max(dp[i][0],dp[i][1]-g[i]),或者要加个g[i]是因为同时建尼姑院要减去一定的信仰值。而这个转移的顺序是怎么实现的?我总不能每次都去找叶子然后再一次次往上更新吧?用拓扑排序一步一步往上更新,直到那些环为止,他们的入边永远不为0.

处理完了触须,我们要开始解剖章鱼真身了。因为是个环,我们不能简单地像前面那样转移,那样的话从i点开始到i点结束的时候i点的状态会很混乱。做这题我想到一种解决环上问题的技巧--拆环。随便从某个点开始就将环拆成链。这题分两种情况进入环,当再碰到这个点时特判下,其他情况转移方程同上。

测试数据:

2
3 -1 2
2 -2 1

4
3 -2 2
4 -3 3
2 -1 1
5 -2 2

4
3 0 2
4 0 3
2 0 1
5 0 2

4
3 -2 2
4 -3 3
2 -2 1
5 -9 2

OutPut:
3
9
14
8

C艹代码:

#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define MAX 110000
#define int64 long long
#define max(a,b) ((a)>(b)?(a):(b))struct node {int val,g,v;
}arr[MAX];
int st[MAX],top,cnt[MAX],tot;            //拓朴排序用
int mmap[MAX],n,flag[MAX];               //flag表示是否为环中的点,dp[i][0]表示不在i建,1表示在i建
int64 dp[MAX][2],power[MAX][2],ans;void Initial() {ans = top = 0;memset(dp,0,sizeof(dp));memset(cnt,0,sizeof(cnt));memset(flag,0,sizeof(flag));memset(power,0,sizeof(power));
}
void Debug_Input(){//printf("top = %d\n",tot);for (int i = 1; i <= n; ++i)printf("power[%d][0]=%d power[%d][1]=%d\n",i,power[i][0],i,power[i][1]);
}
void ToooPooo() {int i,j,k,cur,next;for (i = 1; i <= n; ++i)if (!cnt[i]) st[++top] = i;while (top) {cur = st[top--];tot++;flag[cur] = 1;                  //非环中的点dp[cur][1] += arr[cur].val;        //此处建庙则不管后序的情况加上增加的信仰值next = mmap[cur];          dp[next][0] += max(dp[cur][0],dp[cur][1]);dp[next][1] += max(dp[cur][0],dp[cur][1]+arr[cur].g);cnt[next]--;                if (cnt[next] == 0) st[++top] = next;}
}
void Dfs(int s,int kind) {flag[s] = 1;int next = mmap[s];power[s][1] += arr[s].val;         //此处建庙则不管后序的情况加上增加的信仰值if (!flag[next])  {power[next][0] = dp[next][0];power[next][1] = dp[next][1];power[next][0] += max(power[s][0],power[s][1]);power[next][1] += max(power[s][0],power[s][1]+arr[s].g);Dfs(next,kind);}else {if (kind == 0) power[next][0] = max(power[s][0],power[s][1]);else  power[next][1] = max(power[s][0],power[s][1]+arr[s].g);}if (kind == 0) flag[s] = 0;
}int main()
{int i,j,k;while (scanf("%d",&n) != EOF) {Initial();for (i = 1; i <= n; ++i) {scanf("%d%d%d",&arr[i].val,&arr[i].g,&arr[i].v);cnt[arr[i].v]++;mmap[i] = arr[i].v;}ToooPooo();for (i = 1; i <= n; ++i)if (flag[i] == 0) {int next = mmap[i];dp[i][1] += arr[i].val;int64 temp = max(dp[i][1],dp[i][0]);power[i][0] = dp[i][0];power[i][1] = dp[i][1];power[next][0] = dp[next][0];power[next][1] = dp[next][1];power[next][0] += dp[i][0];power[next][1] += dp[i][0];flag[i] = 1;Dfs(next,0);temp = max(temp,power[i][0]);power[next][0] = dp[next][0];power[next][1] = dp[next][1];power[next][0] += dp[i][1];power[next][1] += dp[i][1] + arr[i].g;flag[i] = 1;Dfs(next,1);ans += max(temp,power[i][1]);}printf("%lld\n",ans);}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

Zoj 3527 Shinryaku! Kero Musume (DP_章鱼图上的树形DP)相关推荐

  1. 图论 ---- C. Nastya and Unexpected Guest(图上最短路dp + 01bfs)

    题目链接 题目大意: 给你一条长度为 n 的马路(可以将马路视为一个数轴),你要从 0 位置开始到达 n 位置,你每秒走 1 个长度单位.在马路上有 m 个安全岛,它们的位置已给定.该马路的绿灯亮 g ...

  2. [USACO Hol10] 臭气弹 图上期望概率dp 高斯

    记住一开始和后来的经过是两个事件因此概率可以大于一 #include<cstdio> #include<iostream> #include<cstdlib> #i ...

  3. ZOJ 3527 树形DP(章鱼图DP)

    题意 有N个村庄,每个村庄有一定的信仰值,占领村庄可以得到信仰值,每个村庄有一个关联村庄,同时占领关联村庄可以得到加成(可能为负),问占领一些村庄,最多可以得到多少信仰值 题解 这个DP已经不能算是树 ...

  4. kido机器人没反应_机器人不能钩的三个英雄,章鱼妈上榜,钩中图四我方直接团灭!...

    话不多说,点赞关注走一波,小伙伴们好我是小贤,欢迎来到<小贤联盟笔记>第十二期,上一期我们讲到了最丢人的几种死法(关注查看历史内容),那么今天我们来说说机器人不能钩的三个英雄,章鱼妈上榜, ...

  5. python 一张图画多条线_Gnuplot.py在一张图上绘制多条线

    我目前正试图使用gnuplot py从文本文件中绘制多行.我可以分别绘制两条线,但当我试图在同一个图上绘制它们时,它只绘制一条线.在 这是我的代码:#!/usr/bin/env python impo ...

  6. tensorboard图上存在直线_高中数学必修二直线与圆:真是让我没想到,他俩的关系还挺不简单...

    为什么有些题目看着复杂,看一眼就想烧了卷子.听老师一讲,然后一个有趣的事情就发生了,原来这么简单,哎哟,这方法不错,老师还挺聪明,给你点个赞. 首先承认一点,大家智商基本没有太大差异,老师也好,学生也 ...

  7. ICML2020 | 基于贝叶斯元学习在关系图上进行小样本关系抽取

    今天给大家介绍来自加拿大蒙特利尔大学Mila人工智能研究所唐建教授课题组在ICML2020上发表的一篇关于关系抽取的文章.作者利用全局关系图来研究不同句子之间的新关系,并提出了一种新的贝叶斯元学习方法 ...

  8. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、在折线图上为每个数据点添加日期数据标签

    Python使用matplotlib函数subplot可视化多个不同颜色的折线图.在折线图上为每个数据点添加日期数据标签 目录

  9. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、在折线图上为每个数据点添加数值标签

    Python使用matplotlib函数subplot可视化多个不同颜色的折线图.在折线图上为每个数据点添加数值标签 目录

  10. R语言ggplot2可视化在箱图上添加分组样本个数

    R语言ggplot2可视化在箱图上添加分组样本个数 目录 R语言ggplot2可视化在箱图上添加分组样本个数 #数据预处理

最新文章

  1. wps 2016 个人版 重新开始编号
  2. 一些重要的 XML DOM 方法概述
  3. 一文详解科研中的Paper阅读方法!!!
  4. Android ListView 滚动翻页效果
  5. zabbix入门到精通之--zabbix proxy配置(二)
  6. 【ArcGIS遇上Python】ArcGIS批量处理栅格影像(NDVI)归一化完整案例代码
  7. python2.7.10安装教程_Linux系统(CentOS)下python2.7.10安装
  8. PE文件的感染C++源代码
  9. java中文件如何加密压缩?
  10. 计算机类系统能力培养试点学校,南昌航空大学获批教育部计算机类专业系统能力培养试点高校...
  11. weblogic创建多个域 及域的配置方法 war包部署及访问测试
  12. H.265 SAO技术
  13. 中国石油大学-《现代应用文写作》第一阶段在线作业
  14. tidb-analyze
  15. wordpress mysql缓存_【新功能】wordpress数据库缓存功能介绍和教程
  16. 鸿蒙开发|呼吸训练实战项目(二)
  17. 普中tft彩屏驱动程序下载_tft彩屏驱动程序
  18. matlab求方程在X附近的根,matlab 实验03 求代数方程的近似根(解)
  19. Java开发记事本(完整版)
  20. C与C++中++i和i++的区别

热门文章

  1. 洛谷P3332 K大数查询
  2. android sd卡 spi,SD卡总结-SPI模式
  3. php 集成 spss,spss怎么导入数据
  4. centos安装aria2c_CentOS安装aria2 + yaaw实现离线下载
  5. Endnote 导出英文、中文(知网)参考文献进入Word
  6. 优雅代码之巧用 Ramda
  7. 使用Word批量删除换行和空白行
  8. linux 用户权限不够,linux .权限不够怎么办
  9. matlab激光扩束总结,zemax笔记14——激光扩束系统的设计
  10. Spark实践的阶段性总结