zoukankan      html  css  js  c++  java
  • 蓝桥杯--- 历届试题 大臣的旅费 (DFS & Vector)

    题目提交链接:http://lx.lanqiao.org/problem.page?gpid=T32

    问题描述

    很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

    为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

    J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

    聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

    J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

    输入格式

    输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

    城市从1开始依次编号,1号城市为首都。

    接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

    每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

    输出格式

    输出一个整数,表示大臣J最多花费的路费是多少。

    样例输入1
    5
    1 2 2
    1 3 1
    2 4 5
    2 5 4
    样例输出1
    135
    输出格式

    大臣J从城市4到城市5要花费135的路费。


    开始的思路是从每一个点出发,求出其最长距离,然后输出就可以了,这样每个节点都会作为开始查找其所有路径的长度,较浪费时间,因为其为树的结构,其实没有必要把每一个节点作为起始节点进行查找。。。

    开始的时候就知道是用树这种数据结构,但是由于是普通树,不太会存储,所以索性就用图了,但是这样的话会浪费掉很多的空间,并且在扫描的时候会全部扫面造成大量的时间浪费,并且图结构的存储造成数组开辟也受到一定的限制,另外最后关键是结果还不正确,一组WR ,一组运行时间错误,估计就是数组的受限原因造成的。。。另外一组的WR现在还不知道具体是错在什么地方,不知道会不会只数组的原因,以后改正。。。

    代码:

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define MAX 1500
    int n,x,y,v,now;
    int Max=-INF;
    int map[1500][1500],dis[1500][1500];
    bool vis[1500];
    long long  sum(int x){
    	return (11+10+x)*x/2;
    }
    
    void dfs(int i,int count){
      vis[i]=1; 
      for(int x=1;x<n;x++){
    	  if(x==i) continue;//
    	  if(map[i][x] && vis[x]==0){
    	       dis[now][x]=dis[x][now]=count+dis[i][x];
    		   dfs(x,count+dis[i][x]);
       	  	   if(Max<dis[now][x]) Max=dis[now][x];
    	  }
      }
      vis[i]=0;
    }
    
    int main (){
      while(cin>>n){
    	Max=-INF;
    	memset(map,0,sizeof(map));
    	memset(dis,0,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	for(int i=0;i<n-1;i++){
    		cin>>x>>y>>v;
    		map[x][y]=map[y][x]=1;
    		dis[x][y]=dis[y][x]=v;
    	}
    	for(int i=1;i<=n;i++){
    		now=i;
            dfs(i,0); 
    	}
    	 cout<<sum(Max)<<endl;	
      }
        return 0;
    }


    另外一种比较恰当的普通建树方式是用vector这样的数据结构进行存储,很好用,也没有什么超时之列的问题。。。

    下面具体说说这道题的思路,由于满足树这样的结构,所以起始先找出距离根节点代价(也就是w值)最远的,然后以这个作为起点遍历,当然就是最长的路径了,起始最终转化为的就是最长路径的查找。具体原因仔细想想就知道了,不太好表达。。。

    为了实现完整的查找,就需要两次的遍历,第一次查找从根节点开始的w消耗值最大的路径,查找出这条路径的终点,然后用该节点作为起始节点再次遍历,这样所获的就是要查找的结果了。。。

    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #define  INF 0x3f3f3f3f
    
    using namespace std;
    vector<int> G[1000005];
    vector<int> E[1000005];
    bool  vis[1000005];
    int d[1000005];
    void init()
    {
        memset(vis, 0, sizeof(vis));  
    }
    void dfs(int u){
        vis[u]=1;
        int size=G[u].size();
        for(int i=0;i<size;i++){
            int v=G[u][i];
            if(!vis[v]){
                 d[v]=d[u]+E[u][i];
                dfs(v);
            }
        }
    }
    int main()
    {
        int n;
        cin>>n; 
        int u,v,w;
        
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            G[u-1].push_back(v-1);
            E[u-1].push_back(w);
            
            G[v-1].push_back(u-1);
            E[v-1].push_back(w);  
        }
        //  第一遍
        init();
        for(int i=0;i<n;i++)
            d[i]=(i==0?0:INF);
        dfs(0);
        int start=0;
        int  max=-1;
        for(int i=0;i<n;i++)
            if(d[i]>max&&d[i]!=INF)
            {
                max=d[i];
                start=i;
                
            }
        init();
        for(int i=0;i<n;i++)
            d[i]=(i==start?0:INF);
        dfs(start);  
        int ans=-1; 
        for(int i=0;i<n;i++)
            if(d[i]>ans&&d[i]!=INF)
                ans=d[i];
        ans=10*ans+ans*(ans+1)/2;   
        cout<<ans<<endl;     
    }

    另外注意Vector的使用是一定注意其下标和输入数据的存储关系,因为在之后的处理过程中,vector数组的下表就是节点,如G[0]就是0这个节点,如果再输入的时候不加改变的把题目给出的节点输入的话就会,就错位了0节点存储的就是1所对应的节点了,上面是从G[0]开始存储的,这样也就减1了,但是稍显麻烦,所以从下表为1的开始存储就直接了,更加明了。。。

    //去掉一下注释行查看详细深搜过程。
    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #define  INF 0x3f3f3f3f
    
    using namespace std;
    vector<int> G[1000005];//建立两个数组vector分别存储节点信息和路径权值
    vector<int> E[1000005];
    bool  vis[1000005];
    int d[1000005];
    
    void dfs(int u){
        vis[u]=1;
        int size=G[u].size();
        for(int i=0;i<size;i++){
            int v=G[u][i];
            if(!vis[v]){
                 d[v]=d[u]+E[u][i];
    //             cout<<"父节点为:"<<u<<"    子节点为:" <<v<<endl;
                dfs(v);
            }
        }
    }
    int main()
    {
        int n;
        while(cin>>n){
            int u,v,w;
            for(int i=0;i<=n;i++){//由于多组测试数据,所以必须清空vector
                G[i].clear();
                E[i].clear();
            }
            for(int i=0;i<n-1;i++)
            {
                scanf("%d%d%d",&u,&v,&w);
                G[u].push_back(v);
                E[u].push_back(w);
                
                G[v].push_back(u); //其实在第一遍的时候使用不到的,只是在之后的逆向搜索的时候才会用到
                E[v].push_back(w);  
            }
            //节点信息输出
    //        for(int i=1;i<=n;i++){
    //          cout<<i<<"子节点为:";
    //          for(int j=0;j<G[i].size();j++)
    //             cout<<G[i][j]<<' ';
    //          cout<<endl;
    //        }
    //        cout<<endl<<endl;
            
            //  第一遍
    //        cout<<endl<<endl<<"第二次遍历过程..."<<endl;
            memset(vis, 0, sizeof(vis));  
            for(int i=0;i<n;i++)
                d[i]=(i==1?0:INF);
            dfs(1);
            int start=1;
            int  max=-1;
            for(int i=1;i<=n;i++)
                if(d[i]>max&&d[i]!=INF)
                {
                    max=d[i];
                    start=i;   
                }
                
            //第二次遍历
    //        cout<<endl<<endl<<"第二次遍历过程..."<<endl;
            memset(vis, 0, sizeof(vis));  
            for(int i=0;i<=n;i++)
                d[i]=(i==start?0:INF);
            dfs(start);  
            int ans=-1;
            for(int i=0;i<=n;i++)
                if(d[i]>ans&&d[i]!=INF)
                    ans=d[i];
            ans=10*ans+ans*(ans+1)/2;   
            cout<<ans<<endl;     
        }    
    }


  • 相关阅读:
    分享一个 @user 前端插件
    .net 的一个分词系统(jieba中文分词的.NET版本:jieba.NET)
    InvokeMember 使用(转http://blog.csdn.net/gooer/article/details/2927113)
    C#反射机制(转自Binfire博客)
    MVC中使用AuthorizeAttribute做身份验证操作
    javascript日期操作详解
    精通 JS正则表达式
    JavaScript 正则表达式
    Js获取当前日期时间及其它操作
    Django 模板中 变量 过滤器的使用方法
  • 原文地址:https://www.cnblogs.com/zswbky/p/5431954.html
Copyright © 2011-2022 走看看