uva1484
2015-06-08 09:16
141 查看
bob和alice
题目描述:
一棵树,bob想要尽量往远的走,alice想要尽量往近的走,并且他们约定走的距离必须是[l,r]内.问bob先走,alice后走,问最终会走到哪里题解:
画出树,发现是递归的不用看具体的子树张什么样的,所以用树形dp.就是奇偶从子树中挑最大的和最小的.关键是:因为有[l,r]的限制,所以要一直有一个road跟踪值,来确保取得的最值是有效[l,r]中的最值,而不是当前u问根开始从0计算长度的最值,防止丢掉有效数.重点:
不用管子树的具体,只用保留一些结果.用树形dp.关键是想清楚[l,r]对全局的限制.代码:
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #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 = 500000+10; const int INF = 1e9 +10; int l, r, n, dp[maxn]; struct info { int to, len, next; }; info edge[maxn*2]; int head[maxn]; int tot; void add_edge(int a, int b, int l)//本题没用vector { edge[tot].len = l; edge[tot].to = b; edge[tot].next = head[a]; head[a] = tot; tot++; } //vector<info> G[maxn]; void dfs(int u, int fa, int bob, int road)//传进去road,但是dp的值没有加上road,因此最值判断要带上road. { if(head[u]==-1)//叶子节点 { if(road <= r&&road>=l)//能够提供情况 { dp[u] = 0; } else//不能提供情况 { dp[u] = -1; } return; } if(bob) { dp[u] = -1; for(int i = head[u];i !=-1;i = edge[i].next) { int v = edge[i].to, len = edge[i].len; if(v!=fa) { dfs(v, u, 1-bob, road + len); if(dp[v]==-1)//有效情况 continue; int t = dp[v] + len; if(t + road >=l&&t+road<=r)//有效情况 { dp[u] = max(dp[u], t); } } } if(dp[u] + road > r||dp[u]+road < l)//没有有效的情况 { dp[u] = -1; } } else//一样的 { dp[u] = INF; for(int i = head[u];i!=-1;i = edge[i].next) { int v = edge[i].to, len = edge[i].len; if(v!=fa) { dfs(v, u, 1-bob, road+len); if(dp[v]==-1) continue; int t = dp[v] + len; if(t + road >=l&&t+road<=r) { dp[u] = min(dp[u], t); } } } // if(road <= r&&road >= l) // { // dp[u] = 0; // } if(dp[u]==INF) { dp[u] = -1; } } } void solve() { dfs(0, -1, 1, 0); if(dp[0] == -1) { printf("Oh, my god!\n"); } else { printf("%d\n", dp[0]); } } int read()//快速读入 { char ch; int ans = 0; ch = getchar(); while(!(isdigit(ch))) { ch = getchar(); } while(isdigit(ch)) { ch = ch-'0'; ans = ch+(ans << 3) + (ans << 1); ch = getchar(); } return ans; } int main() { // freopen("6Fin.txt", "r", stdin); //freopen("6Fout.txt", "w", stdout); while(scanf("%d%d%d", &n, &l, &r) == 3) { memset(head, -1 , sizeof(head)); tot = 0; REP_D(i, 1, n - 1) { int a, b, len; a = read(); b = read(); len = read(); //scanf("%d%d%d", &a, &b, &len); // info t; // t.to = b; // t.len = len; // G[a].push_back(t); // t.to = a; // G[b].push_back(t); add_edge(a, b, len); } solve(); } return 0; }
相关文章推荐
- 利用底层键盘钩子屏蔽任意按键
- Math.round(11.5)等于多少?Math.round(-11.5)等于多少?
- python 使用scapy进行ARP扫描
- C++9.3.8 赋值与swap
- android之layout布局和ListView中的一些属性介绍
- jQuery ui背景色动态渐变导航菜单
- JAVA 面向对象
- ASP.NET中实现把form表单元素转为实体对象或集合
- 程序入口-UIApplicationMain详解
- BZOJ 1600: [Usaco2008 Oct]建造栅栏( dp )
- PHP高级特性二之文件处理
- apscheduler 排程
- java中,什么是GC?GC的基本原理。
- C#的百度地图开发(四)前端显示与定位
- JavaScript高级用法三之浏览器对象
- 海事东北赛&&全国邀请赛总结
- win10去掉快捷方式小箭头 怎么去除桌面图标箭头
- 利用底层键盘钩子拦载任意按键(回调版)
- 【Java GUI】Java面板基础:JPanel
- 理解伪元素 :before 和 :after