【ctsc2010 星际旅行】

来源:互联网 发布:pr ae是什么软件 编辑:程序博客网 时间:2024/04/30 02:39



   题意很简单:

   给定一棵树,问从根分别走到每个节点的最长路程,其中每个点给定lim,即最多从该点出发lim次,保证lim大于等于该点的度数。


   特别“鸣谢”ldl在他的模拟题中出了这道题。

   当题解讲这要用树形dp解网络流模型时,都被惊异了,完全没有想到网络流,也完全没有必要网络流,atm在考场上直接有树形dp AC之,考后hyc也自己YY出了另一种dp方法,

网络流对于这道题真心不知道有什么意义。

   std,atm 和 hyc的dp都有一个无语的问题,那就是细节比较多,转移或统计时要使劲的推啊推,修改啊修改,各种地方的加减使得出错概率很高,对于我这种傻×肯定写起来比较吃力//用atm的方法写了一半,被打断,后来去写就又推不出了。

 

   于是只要YY 啊  YY ,YY出一个几乎没有烦人的细节,甚至没有写dp过程的方法:

    

   正向思维难度很大,发现可以设计一个回退操作,而回退操作对于答案的影响仅为1!
   那么可以先用简单的统计求出从根回到根得到的最大步数,然后用dfs序求解,dfs递归时,等于是要撤销一步操作,分三种情况讨论,只有加1和减1操作,完全没有麻烦的。

    

   方法简单到1A, 在衡八上刷到了rank 1(貌似是头一次)

   http://www.zybbs.org/JudgeOnline/problemstatus.php?id=1917



# include <cstdlib># include <cmath># include <cstdio># include <cstring>using namespace std;const int V = 50000+10, E = 100000+10;int top, linke[E], point[E], next[E];int n, bj[V], d[V], cs[V], ans[V], now;  void link(int x, int y) {++top; next[top]=linke[x];linke[x]=top;point[top]= y;}int min(int x, int y) {return x<y?x:y;};void dfs(int u, int fa){int up, ke;for (ke = linke[u]; ke; ke = next[ke])if (point[ke]!= fa){dfs(point[ke], u);up = min(d[u], d[point[ke]]);d[u] -= up; d[point[ke]] -= up; now += 2*up;if (d[point[ke]]) cs[u] = point[ke];}}void dfs_ans(int u, int fa){int ke; ans[u] = now;for (ke = linke[u]; ke; ke = next[ke])if (point[ke]!= fa){if (d[u] != 0) d[u]--, now++, bj[u] = 1;    else if (cs[point[ke]]!= 0) d[cs[point[ke]]]--, now++, bj[u] = 2;else d[point[ke]]++, now--, bj[u] = 3;dfs_ans(point[ke], u);if (bj[u] == 1) d[u]++, now--;else if (bj[u] == 2)  d[cs[point[ke]]]++, now--;else d[point[ke]]--, now++;}}int main(){int i, x, y;freopen("child.in", "r", stdin);freopen("child.out", "w", stdout);scanf("%d", &n);for (i = 1; i <= n; i++) scanf("%d", &d[i]); for (i = 1; i < n; i++) scanf("%d%d", &x, &y), ++x, ++y, link(x, y), link(y, x), d[x]--, d[y]--, now += 2;dfs(1, 0); dfs_ans(1, 0);for (i = 1; i <= n; i++) printf("%d\n", ans[i]);return 0;}



原创粉丝点击