Road Trip

描述

Robert Prim and Joseph Kruskal have started a traveling band during their sabbatical. They hope to hit it big, but at the moment they’re making even less money than before. This tight budget makes it difficult to plan their debut tour. They’d like to visit every major city in their state and return to the city they started at, but after considering the cost of renting each venue, they’ve discovered that they’ll have to skip one of the cities. As they don’t have an incredibly reliable nor comfortable vehicle to travel in, they’ve decided to exclude the city that will result in the shortest road trip. Since Prim and Kruskal hate cycles, they’ve already narrowed down the roads they plan to use for their trip such that there are no cycles whatsoever, yet they can still reach each city. The question is, what’s the length of their optimal trip?

输入

The first line is the number K of input data sets, followed by the K data sets, each of the following form:
The first line of each data set contains two integers V and E, the number of cities and the number of roads, respectively, where 2 ≤ V ≤ 100 and 1 ≤ E ≤ 100.
This is followed by E lines, each describing a 2-way road. Each line has three integers ai, bi, di where 1 ≤ ai, bi ≤ V are the cities at the endpoints of road i and di is its length. Prim and Kruskal always start at city 1, and there are no cycles in the graph (other than the fact they can repeatedly go back and forth on the same road).

输出

For each data set, output “Data Set x:” on a line by itself, where x is its number. On the next line, output the minimum distance they will travel assuming they skip the correct city, hit every other city, and return to where they began.

样例输入

1
5 4
1 2 3
2 3 7
3 4 3
3 5 4

样例输出

Data Set 1:
26

题意:
给定一张无环(划重点)无向图,求去掉一个点使得从1开始经过除了去掉的点之外所有点并回到1点的最小距离。
思路:
一开始被题目吓坏了,以为是个难题,想了好久。第一次思考无果后,再次读题,看到重点——无环。发现,唉~这表面上是个图其实是棵树,那题目的答案不就是所有树边和的再减去最大叶子节点边最后乘2吗?
再简单分析下:题目给定的是一棵树,要满足祛除一个点并保证遍历所有其他点,那么祛除的点就只能是叶节点,问题得到简化;由于是树那么,从点1到达其他点就只有一条路径,很显然最短的路线就是从父节点出发到达某个子节点,然后再回到父节点,接着在对其他子节点重复这个过程,问题得到大简化;因为去掉的是叶节点,所以它的祛除不会对到达其他点的路径产生影响,所以答案应是(树边和 - 最大叶节点到其父节点的边)*2.

代码(比较菜,写的有点长。。。):

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
struct node
{
    int pt,val;
};
vector<node>G[105];
bool vis[105];
int skip,sum;
void dfs(int u)
{
    int n,v,f=0;
    n=G[u].size();
    for(int i=0;i<n;i++)
    {
        v=G[u][i].pt;
        if(vis[v])continue;
        vis[v]=true;
        f++;
        dfs(v);
        sum+=2*G[u][i].val;
    }
    if(!f)
    {
        skip=max(skip,2*G[u][0].val);
    }
    return ;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int no=1;no<=t;no++)
    {
        int n,m,a,b,v;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)G[i].clear(),vis[i]=0;
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&v);
            G[a].push_back({b,v});
            G[b].push_back({a,v});
        }
        vis[1]=true;skip=sum=0;
        printf("Data Set %d:\n",no);
        dfs(1);
        printf("%d\n",sum-skip);
    }
}

若有什么错误,欢迎指正^ _ ^ 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用分支界限法解决该问题的C++代码: ```c++ #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int N = 1010, M = 20010; int n, m, c, s, e; int p[N], h[N], e[M], ne[M], w[M], idx; int dist[N][110]; // dist[i][j]表示从起点到i,油量为j时的最短路 bool st[N][110]; struct Node { int u, d, c; bool operator< (const Node& t) const { return d > t.d; } }; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++; } int dijkstra() { memset(dist, 0x3f, sizeof dist); priority_queue<Node> heap; heap.push({s, 0, 0}); dist[s][0] = 0; while (heap.size()) { auto t = heap.top(); heap.pop(); int u = t.u, d = t.d, c = t.c; if (st[u][c]) continue; st[u][c] = true; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i], v = w[i]; if (c + j <= c && dist[j][c + j] > dist[u][c] + p[j] * (c + j - d)) { dist[j][c + j] = dist[u][c] + p[j] * (c + j - d); heap.push({j, dist[j][c + j], c + j}); } } } int res = 0x3f3f3f3f; for (int i = 0; i <= c; i ++ ) res = min(res, dist[e][i]); if (res == 0x3f3f3f3f) return -1; return res; } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i ++ ) scanf("%d", &p[i]); memset(h, -1, sizeof h); while (m -- ) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c), add(b, a, c); } scanf("%d%d%d", &c, &s, &e); int res = dijkstra(); if (res == -1) puts("impossible"); else printf("%d\n", res); return 0; } ``` 思路解析: - 由于题目要求求最优解,因此我们可以想到使用单源最短路径算法来求解,这里我们采用Dijkstra算法。 - 由于油量对于最短路的计算有影响,因此我们可以使用二维数组`dist[i][j]`来表示从起点到i,油量为j时的最短路。 - 在Dijkstra算法中,每次从堆中取出距离起点最近的节点`u`,在遍历`u`的邻居节点`v`时,我们需要考虑两种情况:(1)当前油量`c`可以到达节点`v`,则直接更新`dist[v][c]`;(2)当前油量`c`无法到达节点`v`,则需要选择一个新的油量`c'`来到达节点`v`,那么节点`v`的油量将变为`c' - dis(u, v)`,因此我们可以将更新`dist[v][c']`的过程转化为更新`dist[v][c]`的过程,即`dist[v][c'] = dist[u][c] + p[v] * (c' - dis(u, v))`,其中`p[v]`表示节点`v`的油价。 - 由于油量是一个连续的值,因此我们需要使用bool数组`st[i][j]`来标记节点`i`的油量是否被访问过,防止重复访问。 - 最后,我们在`dist[e][i]`中取最小值即为答案。 时间复杂度:$O(mc\log n)$ 其中,$m$为边数,$c$为油量,$n$为点数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值