恐怖分子炸桥
来源:互联网 发布:mysql alter trigger 编辑:程序博客网 时间:2024/06/02 14:31
HDU - 4679
题目描述:
n~1e5个点的树,边的长度都是1,但是每一条边都有一个破坏的值,恐怖分子可以随便破坏一条边,剩下两棵书的直径的较大值*破坏边的值设为t,求所有的边中最小的t对应的id,如果一样的话输出较小的id
题解:
计算一棵树上,去掉一条边之后剩下的两棵树分别的直径.首先,求u为根子树的直径很好求:先搞出来距离dpm和dps,然后再dfs之后就搞出了直径.第二:是重点.就像2说的,要去掉u,并且要考虑u的兄弟,因此我们不能定fa为f[fa],因为这样过答案f要包含fa的一些儿子,违反了2中的规则.于是定f[u],含义是去掉u本身及u的儿子之后的树的最长直径.那么下面就是如何从u推到v.看v的答案组成,包含u的答案,之后是u的非v的儿子们的最长直径,之后是和u相关的,就是u向上的最长链和u非v的两条最长链挑出两个组成.u向上的最长链经常搞.这样就搞出来了.因此需要向下的3条链,儿子中2个最大的直径.下面的代码因为只存了1个u为根直径,因此每次都要再遍历一次找出儿子的2个最大的直径….
重点:
超级多dp的树形dp
重点是从上往下的树形dp,f[u]表示的是去掉u并且去掉u的儿子们的最大直径,然后从dfs的时候u已经搞定了,去搞定v. u->推v.
代码:
#pragma comment(linker,"/STACK:102400000,102400000")#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e5 + 10;const int INF= 1e9 + 100;int dp[maxn][3], n;int dia[maxn];int ans, ans_i;struct edge{ int a, b, w;};edge p[maxn];struct info{ int to, no;};vector<info> G[maxn];void gao(int &a, int &b, int &c, int t)//好写一点,更新三个大值{ if(t > a) { c = b; b = a; a = t; } else if(t > b) { c = b; b = t; } else if(t > c) { c = t; }}void dfs_dp(int u, int fa)//搞出3个最大的到叶子的{ for(int i = 0; i <= 2; i++) { dp[u][i] = 0;//初始化为0,因为只要为0,路径一定不相交 } REP(i, 0, G[u].size()) { int v = G[u][i].to; if(fa!=v) { dfs_dp(v, u); int tmp = dp[v][0] + 1; gao(dp[u][0], dp[u][1], dp[u][2], tmp); } }}void dfs_dia(int u, int fa)//搞出u子树上的直径{ int d = 0; dia[u] = 0; REP(i, 0, G[u].size()) { int v = G[u][i].to; if(v!=fa) { dfs_dia(v, u); } d = max(d, dia[v]); } d = max(d, dp[u][0]+dp[u][1]); dia[u] = d;}void dfs(int u, int fa, int u_ans, int u_l, int ans_id){ if(fa != 0)//第一次不用算结果 {//这是算结果用的,因为u的f定义已经得到答案了,因此可以算答案了. int t = max(u_ans, dia[u])*p[ans_id].w; if(t < ans) { ans = t; ans_i = ans_id; } else if(t == ans) { ans_i = min(ans_i, ans_id); } } int diam = 0, dias = 0; int nouse = 0; REP(i, 0, G[u].size())//先遍历一遍,如果已经存过两个直径,就不用遍历了 { int v = G[u][i].to; if(v==fa) continue; gao(diam, dias, nouse, dia[v]); } //int uforv_l = u_l; REP(i, 0, G[u].size())//重点开始 { int v = G[u][i].to; int id = G[u][i].no; if(v==fa) continue; int v_ans = u_ans;//v_ans的第一个组成 if(diam==dia[v])//第二个 { v_ans = max(v_ans, dias); } else { v_ans = max(v_ans, diam); } int a, b;//第三个 if(dp[u][0]==1+dp[v][0]) { a = dp[u][1]; b = dp[u][2]; } else if(dp[u][1] == 1+dp[v][0]) { a = dp[u][0]; b = dp[u][2]; } else { a = dp[u][0]; b = dp[u][1]; } v_ans = max(a+b, v_ans); v_ans = max(a+u_l, v_ans); dfs(v, u, v_ans, 1 + max(a, u_l), id);//v_l很容易就算出来了 }}void solve(){ dfs_dp(1, 0); dfs_dia(1, 0); ans = INF; dfs(1, 0, 0, 0, 0); printf("%d\n", ans_i);}int main(){ freopen("8Hin.txt", "r", stdin); //freopen("6Fout.txt", "w", stdout); int ncase; scanf("%d", &ncase); for(int _ = 1; _ <= ncase; _++) { printf("Case #%d: ", _); scanf("%d", &n); REP_D(i, 1, n) { G[i].clear(); } REP_D(i, 1, n - 1) { int a, b, w; scanf("%d%d%d", &a, &b, &w); p[i].a=a; p[i].b=b; p[i].w=w; info t; t.to = b; t.no = i; G[a].push_back(t); t.to = a; G[b].push_back(t); } solve(); } return 0;}
0 0
- 恐怖分子炸桥
- 一个上网的恐怖分子不是好恐怖分子
- 动物恐怖分子集中营[组图]
- 基地组织派五名恐怖分子
- 被恐怖分子抓去写程序...
- 【图论】【RQNOJ】恐怖分子
- [Rqnoj-77]恐怖分子
- 恐怖分子偷走英国政府的手机
- Google Maps成为恐怖分子帮凶?
- 恐怖分子在广州(转帖笑话)
- 昆明:暴恐案系东突分裂恐怖分子策划实施
- 11恐怖分子涉参与马航案被捕
- 美国智囊团:恐怖分子和集团可能会…
- [双语阅读]FBI头号恐怖分子名单首次出现美国人
- 马航客机为何难找 美媒猜被恐怖分子导弹击落
- 大疆在中东设禁飞区,防止被恐怖分子利用
- 恐怖分子在广州!(纯搞笑,娱乐一下,我想广州也不会这么夸张)
- Polo. Small, but tought (一个选择了POLO的倒霉恐怖分子)
- ov3640摄像头
- ios隐藏数字键盘 --在数字键盘左下角添加“完成”按钮的实现原理
- json测试
- Json 转换成 NSDictionary
- C++关于类成员函数指针的正确写法
- 恐怖分子炸桥
- Docker 简介
- 自定义dialog 出现的问题总结
- 主动代码修改约束
- 实时股票数据接口
- 学习编程之智商和情商并用法则
- Opencv练习题3-7
- gcc llvm lld
- 转 JDBC批处理Select语句