HDU3001(KB2-J 状态压缩dp)

本文介绍了一个旅行问题的求解算法,旨在寻找访问指定城市且每个城市最多访问两次的最经济路径。通过动态规划方法实现,考虑了不同城市的连接道路及费用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Travelling

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8103    Accepted Submission(s): 2642

Problem Description

After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best choice!He has decided to visit n cities(he insists on seeing all the cities!And he does not mind which city being his start station because superman can bring him to any city at first but only once.), and of course there are m roads here,following a fee as usual.But Mr Acmer gets bored so easily that he doesn't want to visit a city more than twice!And he is so mean that he wants to minimize the total fee!He is lazy you see.So he turns to you for help.
 

 

Input

There are several test cases,the first line is two intergers n(1<=n<=10) and m,which means he needs to visit n cities and there are m roads he can choose,then m lines follow,each line will include three intergers a,b and c(1<=a,b<=n),means there is a road between a and b and the cost is of course c.Input to the End Of File.
 

 

Output

Output the minimum fee that he should pay,or -1 if he can't find such a route.
 

 

Sample Input

2 1 1 2 100 3 2 1 2 40 2 3 50 3 3 1 2 3 1 3 4 2 3 10
 

 

Sample Output

100 90 7
 

 

Source

 
 1 //2017-08-19
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 
 7 using namespace std;
 8 
 9 const int N = 15;
10 const int INF = 0x3f3f3f3f;
11 int G[N][N], n, m, pow3[N], dp[N][60000];//dp[i][S]表示到达节点i,状态为S时的最小费用
12 
13 //询问节点i在状态S下经过了几次。将状态压缩为一个三进制数。
14 int query(int i, int S){
15     return (S/pow3[i])%3;
16 }
17 
18 int main()
19 {
20     //预处理3的次方,pow3[n]表示3的n次方。
21     pow3[0] = 1;
22     for(int i = 1; i < N; i++)
23           pow3[i] = pow3[i-1]*3;
24     while(scanf("%d%d", &n, &m)!=EOF){
25         int u, v, w;
26         memset(G, INF, sizeof(G));
27         memset(dp, INF, sizeof(dp));
28         for(int i = 0; i < m; i++){
29             scanf("%d%d%d", &u, &v, &w);
30             u--; v--;//节点从0到n-1编号。
31             G[u][v] = G[v][u] = min(G[u][v], w);//去重边
32         }
33         //初始化dp,因为每一个点都可以作为起点,所以到达i节点1次的最小费用为0。
34         for(int i = 0; i < n; i++)
35               dp[i][pow3[i]] = 0;
36         int ans = INF;
37         for(int S = 0; S < pow3[n]; S++){
38             bool fg = true;
39             for(int i = 0; i < n; i++){
40                 //检查是否每个节点都已经经过
41                 if(query(i, S) == 0){
42                     fg = false;
43                     continue;
44                 }
45                 //转移到下一个节点
46                 for(int v = 0; v < n; v++){
47                     if(query(v, S) == 2)
48                           continue;
49                     dp[v][S+pow3[v]] = min(dp[v][S+pow3[v]], dp[i][S]+G[i][v]);
50                 }
51             }
52             if(fg){
53                 for(int i = 0; i < n; i++)
54                       ans = min(ans, dp[i][S]);
55             }
56         }
57         if(ans == INF)printf("-1\n");
58         else printf("%d\n", ans);
59     }
60 
61     return 0;
62 }

 

转载于:https://www.cnblogs.com/Penn000/p/7398063.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值