hihoCoder 1168 运输货物

来源:互联网 发布:mysql acos函数 编辑:程序博客网 时间:2024/04/28 12:35

#1168 : 运输货物

时间限制:2000ms
单点时限:1000ms
内存限制:256MB

描述

Z国有n个城市,编号为1, 2, …, n。城市间通过n – 1条道路相连,任意两个城市间有且仅有一条路径可以相互到达。每个城市都有一些货物,政府希望将所有的货物运送到港口城市s以便出口。由于交通条件限制,每一条道路上单位时间只能通过1单位量的货物,这导致运输所有货物可能非常耗时。因而,政府希望知道,最快什么时候能将所有货物运送到港口。

输入

第一行一个整数T,表示数据组数,以下是T组数据。

每组数据第一行有两个整数n和s,表示城市个数和港口城市的编号。接下来n - 1行每行两个整数i和j,表示城市i和j之间有一条道路。接下来n行每行一个数x,表示各城市的货物数量。

输出

对每组数据输出一行"Case #X: Y",X表示数据编号(从1开始),Y为完成运输任务的最短时间。

数据范围

1 ≤ T ≤ 20

小数据

1 ≤ n ≤ 500

0 ≤ x ≤ 20

大数据

1 ≤ n ≤ 100000

0 ≤ x ≤ 100000


题解:

1.把货物的终点记作root,对于root的每一个孩子节点1,2,3....,求出.t1,t2,t3...。t1的含义是将货物从1及其子树运

往root所用的时间(1子树的上载时间),那么总时间便是max(t1,t2,t3...)

2.那么我们如何求t1呢,首先想,如果没有节点的货物量是0,就能保证每个边总是有货物需要运的,t1便是这些节点

货物量之和

3.但是如果某些节点的货量是0,那么有可能就出现边闲置的问题,(想一想为什么?)

4.怎么解决呢,如果我们暴力的解决,就是每一秒钟,枚举各节点货物量的变化,直到所有节点的值都为0

5.还可以这样想,把节点分层,(距离跟节点1条边,2条边。。。),每过一秒,就有下面一层的货物运向上面一层

6.

一条横线代表一层,考虑这棵树,标号代表城市的货物量,

第1秒,没有货物可以上载,出现空闲

第2秒,正好有一个货物可以上载,没有出现空闲

第3秒,可以上载

第4秒,出现空闲

第5,6秒,上载完成

总上载时间就是货物量+空闲的时间

7.空闲的时间的可以推断出,如果第i层没有货物,且0-i层没有排队延迟,就会导致空闲

8.算出每一层的排队延迟,再与没有货物的曾作比较,就可以算出最后的空闲时间了


总结:

1.感觉这个题目是真心很好,比赛结束1分钟的时候才改对这个题目,真是可惜,还需要提高速度啊

2.最近考试算法分析,再跟同学讨论动态规划的时候突然感悟,突然觉得动态规划很多时候就是对枚举的优化,记录

那些需要重复运算的点,避免不必要的操作。推广感觉很多题目都是这样的!

3.这个题目刚开始总猜dfs深搜来做,后来突然感悟用分层做出来的,总结下来的思考方式也是:从暴力枚举优化到

dfs预处理分层来做这个题

4.感悟很多,好题,还需要继续努力


#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;typedef long long LL;#define MAXN 100005int num[MAXN],first[MAXN],deepest,n,e,root,_;LL d[MAXN];struct Edge{    int v,next;}edge[MAXN << 1];void insert(int u,int v){    edge[e].next = first[u];    edge[e].v = v;    first[u] = e++;}void dfs(int u,int fa,int deep){    if(num[u])deepest = max(deepest,deep);    d[deep] += num[u];    for(int i = first[u];i != -1;i = edge[i].next)    {        int v = edge[i].v;        if(v == fa)continue;        dfs(v,u,deep + 1);    }}int main(){    for(int kcas = scanf("%d",&_);kcas <= _;kcas++)    {        e = 0;        memset(first,-1,sizeof(first));        memset(d,0x3f,sizeof(d));        scanf("%d%d",&n,&root);        for(int i = 1;i < n;i++)        {            int u,v;            scanf("%d%d",&u,&v);            insert(u,v);            insert(v,u);        }        for(int i = 1;i <= n;i++)            scanf("%d",&num[i]);        LL ans = 0;        for(int i = first[root];i != -1;i = edge[i].next)        {            int v = edge[i].v;            deepest = 0;            memset(d,0,sizeof(d));            dfs(v,root,0);            LL t1 = 0,t2 = 0;            for(int i = 0;i <= deepest;i++)            {                t1 += d[i];                if(d[i] == 0 && t1 + t2 <= i)                    t2++;            }            ans = max(t1 + t2,ans);        }        printf("Case #%d: %lld\n",kcas,ans);    }}


0 0