bestcoder Round#52 1001(最短路+状压dp)

求从1点出发,走遍所有的点,然后回到1点的最小代价。

每个点可以走若干遍。

如果每个点只能走一遍,那么设dp[i][s]为走完s状态个点(s是状态压缩),现在位于i的最小花费。

然后枚举从哪个点回到原点即可。

但是现在每个点不止走一次,那么状态就不好表示了,但是,我们可以用floyd处理出任意两点的最短距离。

这样子,可以用上面的方式求解了。

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 #pragma comment(linker, "/STACK:1024000000,1024000000")
 16 typedef __int64 LL;                   
 17 const int INF = 100000000;
 18 /*
 19 
 20 
 21 
 22 */
 23 int dp[17][70000];
 24 int dist[20][20];
 25 int g[20][20];
 26 void input(int &x)
 27 {
 28     char ch = getchar();
 29     while (ch<'0' || ch>'9')ch = getchar();
 30     x = 0;
 31     while (ch >= '0'&&ch <= '9')
 32     {
 33         x = x * 10 + ch - '0';
 34         ch = getchar();
 35     }
 36 }
 37 int ans;
 38 
 39 int main()
 40 {
 41     //freopen("d:/1.in", "r", stdin);
 42     int t, n, m, u, v,dis;
 43     scanf("%d", &t);
 44     while (t--)
 45     {
 46         scanf("%d%d", &n, &m);
 47         for (int i = 0; i <= n; ++i)
 48         for (int j = 0; j <= n; ++j)
 49         {
 50             g[i][j] = INF;
 51         }
 52         for (int i = 0; i < m; ++i)
 53         {
 54             input(u);
 55             input(v);
 56             input(dis);
 57             u--;
 58             v--;
 59             if (g[u][v]>dis)
 60                 g[u][v] = g[v][u] = dis;
 61         }
 62         for (int k = 0; k < n; ++k)
 63         {
 64             for (int i = 0; i < n;++i)
 65             for (int j = 0; j < n; ++j)
 66                 g[i][j] = min(g[i][j],g[i][k]+ g[k][j]);
 67         }
 68         
 69         
 70         for (int i = 0; i <= n; ++i)
 71         for (int s = 0; s < (1 << n); ++s)
 72             dp[i][s] = INF;
 73         dp[0][1] = 0;
 74         for (int s = 1; s < (1 << n); ++s)
 75         {
 76             for (int i = 0; i < n; ++i)
 77             {
 78                 if (s&(1 << i))
 79                 {
 80                     for (int j = 0; j < n; ++j)
 81                     {
 82                         if (!(s&(1 << j)))
 83                         {
 84                             dp[j][s | (1 << j)] = min(dp[j][s | (1 << j)], dp[i][s] + g[i][j]);
 85                         }
 86                     }
 87                 }
 88             }
 89         }
 90         if (n == 1)
 91         {
 92             printf("%d\n", 0);
 93             continue;
 94         }
 95         int ans = INF;
 96         for (int i = 1; i < n; ++i)
 97         {
 98             ans = min(dp[i][(1 << n) - 1] + g[i][0], ans);
 99         }
100         printf("%d\n", ans);
101     }
102     return 0;
103 }
View Code

 

转载于:https://www.cnblogs.com/justPassBy/p/4751058.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值