入门OJ:扫雪

Posted akura

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了入门OJ:扫雪相关的知识,希望对你有一定的参考价值。

扫雪1

题目描述
大雪履盖了整个城市,市政府要求冬季服务部门尽快将一些街道(列在一份清单中)的积雪清除掉以恢复交通,整个城市由许多交叉路口和街道构成,当然任意两个交叉路口都是直接或间接连通的,清单给出了最少的街道,使得这些街道的积雪清除后任意两个交叉路口之间有且仅有一条通路,冬季服务部门只有一辆铲雪车及一名司机,这辆铲雪车的出发点位于某个交叉路口。
无论街道上有没有积雪,铲雪车每前进一米都要消耗一升燃料,冬季服务部门要求司机在铲除清单上的所有街道的积雪的前提下,要求消耗燃料最少,积雪铲完后车可以停在任意的交叉路口。
输入格式
输入文件的第一行包含两个整数N和S,1≤N≤100000,1≤S≤N。N为交叉路口的总数;S为铲雪车出发的路口序号。路口的标号为1••N。
接下来的N-1行为清单上的街道,每一行包含三个用空格隔开的整数A、B、C,表示一条从交叉路口A到交叉路口B的街道,C为该街道的长度,单位为米,1≤C≤1000。
输出格式
输出文件仅一行包含一个整数表示清除所有积雪所需的最少的燃料数量。

根据题意,扫雪车在去往一棵子树扫雪之后是还会再回到根的位置。也就是说,子树上的边会被经过两次。而最后的时候扫雪车走到了某个叶子节点是不用再回来的,也就是从根到这个节点的路径上的边只会被经过一次。设所有边权之和为sum,从根节点到最后一个叶子节点的路径长度为len,那么答案就是sum*2-len。其中sum可以在输入时算出,是定值,我们只需让len尽可能大即可。我们可以算出根到所有节点的距离(也可以看成是深度),取最大值即可。复杂度为O(n)。
 
 
 
xxxxxxxxxx
 
 
 
 
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100001
using namespace std;

struct edge{
    int to,dis,next;
    edge(){}
    edge(const int &_to,const int &_dis,const int &_next){
        to=_to,dis=_dis,next=_next;
    }
}e[maxn<<1];
int head[maxn],k;
inline void add(const int &u,const int &v,const int &w){
    e[k]=edge(v,w,head[u]);
    head[u]=k++;
}

int dep[maxn],n,s,sum;//dep[i]表示根到i的距离
void dfs(int u,int pre){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==pre) continue;
        dfs(v,u);
        dep[u]=max(dep[u],dep[v]+e[i].dis);
    }
}

int main(){
    memset(head,-1,sizeof head);
    scanf("%d %d",&n,&s);
    for(register int i=1;i<n;i++){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        add(u,v,w),add(v,u,w);
        sum+=w;
    }
    dfs(s,0);
    printf("%d\n",sum*2-dep[s]);
    return 0;
}
 


扫雪2

跟扫雪1唯一的不同是现在有两辆车。

类比着扫雪1的做法,设边权之和为sum,第一辆扫雪车停的叶子节点到根的距离为len1,第二辆的为len2,答案就是sum*2-len1-len2,我们只需让len1+len2尽可能大即可。类似地,我们可以用扫雪1的做法求出len1和len2,再代进答案式子即可。不过这样做要判断len1的路径和len2没有交点,挺麻烦的。不过既然是两条不同的路径接在一起之后要尽可能地大,不难想到len1+len2就是直径。所以我们求出直径即可。dfs和dp求直径皆可,时间复杂度都是O(n)。
 
 
 
xxxxxxxxxx
 
 
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100001
using namespace std;

struct edge{
    int to,dis,next;
    edge(){}
    edge(const int &_to,const int &_dis,const int &_next){
        to=_to,dis=_dis,next=_next;
    }
}e[maxn<<1];
int head[maxn],k;
inline void add(const int &u,const int &v,const int &w){
    e[k]=edge(v,w,head[u]);
    head[u]=k++;
}

int f[maxn],len,n,s,sum;
void dp(int u,int pre){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==pre) continue;
        dp(v,u);
        len=max(len,f[u]+f[v]+e[i].dis);
        f[u]=max(f[u],f[v]+e[i].dis);
    }
}

int main(){
    memset(head,-1,sizeof head);
    scanf("%d %d",&n,&s);
    for(register int i=1;i<n;i++){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        add(u,v,w),add(v,u,w);
        sum+=w;
    }
    dp(1,0);
    printf("%d\n",sum*2-len);
    return 0;
 
 
}
 

以上是关于入门OJ:扫雪的主要内容,如果未能解决你的问题,请参考以下文章

二分图匹配入门专题1I - Hiding Gold light oj 1152二分图匹配-------------------我是终于不那么水的水题分割线------------------(代码片

九度oj 题目1397:查找数段

入门OJ1044:字母三角形

推荐net开发cad入门阅读代码片段

入门OJ1045:字符图形1-星号矩形

Python OJ 从入门到入门基础练习 10 题