广大暑假训练1 E题 Paid Roads(poj 3411) 解题报告

本文介绍了如何解决POJ 3411问题,涉及最小成本路径算法的核心概念和实现步骤。通过邻接表结构进行深度优先搜索,考虑重复路径的优惠策略,同时运用剪枝技巧优化搜索过程。最后,通过实例代码演示了算法的实现,包括输入输出格式和关键逻辑。

题目链接:http://poj.org/problem?id=3411

题目意思:N个city 由 m 条路连接,对于一条路(假设连接Cityia和 Cityb),如果从Citya 去 Cityb的途中,之前已经走过Cityc(可能会等于a),那么就可以交p的钱,否则之前未走过Cityc,就一定要交r 的路费啦。

      注意,一个点可以被反复多次走,也就是可能构成环,虽然路走长了,但路费便宜了,这个问题要考虑到。还有就是剪枝啦:如果当前求得的路费比以前求得的答案要大,那就要回溯。

      mincost 明明是全局变量,多手在main里又重新声明,搞了我1个多小时才发现 = =....

      

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 1000 + 5;
 8 int head[maxn];
 9 int point_vis[maxn];
10 int N, m, mincost;
11 
12 struct adjlist   // 邻接表
13 {
14     int b, c, p, r;
15     int next;
16 }node[maxn];
17 
18 void dfs(int next, int cost)
19 {
20     if (point_vis[next] > N || cost >= mincost)   // 某一点被经过的次数多于N 或者当前cost比之前求出的minsum要大就回溯
21         return;
22     if (next == N)
23     {
24         mincost = cost;
25         return;
26     }
27     for (int i = head[next]; i != -1; i = node[i].next)
28     {
29         int v = node[i].b;
30         point_vis[node[i].b]++;
31         if (point_vis[node[i].c] >= 1)    // 之前这个中间点c有访问过,就可以交纳在点c的费用p
32             dfs(node[i].b, cost+node[i].p);
33         else      // 之前该点木有走过,只能乖乖交 r 这个费用了
34             dfs(node[i].b, cost+node[i].r);
35         point_vis[node[i].b]--;    
36     }
37 }
38 
39 int main()
40 {
41     while (scanf("%d%d", &N, &m) != EOF)
42     {
43         int t1, cnt = 0;
44         memset(head, -1, sizeof(head));
45         for (int i = 0; i < m; i++)
46         {
47             scanf("%d", &t1);
48             node[cnt].next = head[t1];
49             scanf("%d%d%d%d", &node[cnt].b, &node[cnt].c, &node[cnt].p, &node[cnt].r);
50             head[t1] = cnt++;
51         }
52         memset(point_vis, 0, sizeof(point_vis));
53         mincost = maxn;
54         point_vis[1]++;
55         dfs(1, 0);
56         if (mincost == maxn)
57             printf("impossible\n");
58         else
59             printf("%d\n", mincost);
60     }
61     return 0;
62 }

 

      

转载于:https://www.cnblogs.com/windysai/p/3885969.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值