最短的旅程

在Byteland有n个城市(编号从1到n),它们之间通过双向的道路相连。Byteland的国王并不大方,所以,那里只有n -1条道路,但是,它们的连接方式使得从任意城市都可以走到其他的任何城市。

一天,starhder到了编号为k的城市。他计划从城市k开始,游遍城市m1,m2,m3,……,mj(不一定要按这个顺序旅游),其中j个城市都是不同的,并且也与k不同。Starhder—— 就像每一个旅行家一样,携带的钱总是有限的,所以,他要以最短的路程旅行完所有的城市(从城市k开始)。 于是,他请你帮助计算一下,旅游完上述的城市最短需要多少路程。

 

输入参数

 

第一行输入两个整数,即上文中的n和k,以一个空格隔开。下面的n-1行每行描述一条路,每行输入3个整数ai,bi,di,相邻两个数用一个空格隔开(1<= ai,bi<= n,1<= di<= 1000),ai和bi是用道路直接相连的城市编号,di是这条道路的长度。 第n + 1行输入一个整数j,是starhder要旅游的城市数(1<= j <= n - 1),接下来一行包含j个不同的整数,即m1,m2,……,mj,每两个相邻的整数用一个空格隔开,表示starhder想要去的城市。(1<= mt<=n,mt 不等于k)。

 

输出参数

 

输出只有一行,包含一个整数:starhder旅游的最短路程。

 

样例输入

4 2

1 2 1

4 2 2

2 3 3

2

1 3

样例输出

5


思路:题目中说n个节点总共有n-1条路,所以是一个棵树。先用Floyd求出各节点之间的最短路径,然后将不用去的节点去掉,之后就可以只用剩下的节点求出所要去的最短路径。我用的是暴力搜索,复杂度有点高。


 #include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <vector>
 using namespace std;
 #define M 1050
 #define inf 0xfffffff
 int map[M][M],n,k,city;
 bool go[M];          //go[i]表示去没去过城市i
 int ans;

 void init()
 {
     for(int i=1;i<=n;i++)
     {
        for(int j=1;j<=i;j++)
            map[i][j]=map[j][i]=inf;
        go[i]=1;                      //初始化都是去过的,然后输入想去哪些城市,把他们变成没去过
     }
 }
 void floyd()                     //先求出各城市之间的最短路径
 {
     for(int t=1;t<=n;t++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                map[i][j]=min(map[i][j],map[i][t]+map[t][j]);
 }
 void dfs(int st,int num,int sum)                    //用已知最短路径的图搜索求出最小的路程
 {
     if(num==city)
     {
        ans=min(ans,sum);
        return;
     }
     for(int j=1;j<=n;j++)
     {
         if(!go[j])
         {
            go[j]=1;
            dfs(j,num+1,sum+map[st][j]);
            go[j]=0;                          //每个路径不能互相影响,所以不能忘记要复制回来
         }
     }
 }
 int main()
 {
     int s,e,d;
     while(~scanf("%d%d",&n,&k))
     {
         init();
         ans=inf;
         for(int i=1;i<=n-1;i++)
         {
             scanf("%d%d%d",&s,&e,&d);
             map[s][e]=map[e][s]=d;
         }
         floyd();
         scanf("%d",&city);
         for(int i=0;i<city;i++)
         {
             scanf("%d",&s);
             go[s]=0;
         }
 /*        for(int i=1;i<=n;i++)
         {
            for(int j=1;j<=n;j++)
                printf("%d ",map[i][j]);
            printf("\n");
         }*/
         dfs(k,0,0);
         printf("%d\n",ans);
     }
     return 0;
 }
/*
6 2
1 2 1
1 3 1
2 4 2
3 5 2
5 6 2
3
3 4 5
*/


  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值