zoukankan      html  css  js  c++  java
  • hdu3001 Travelling 旅行商问题 状态压缩DP

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3001

    Travelling

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


    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
     
    题意:还是旅行商问题。这个人要去旅行放松,去n个城市,从哪里出发都可以,但是每个地方最多经过两次,求经过每个点的路线的最小花费。如果不行,则输出-1.
    分析:还是用dp[i][j]来表示状态为i的时,终点为j时候的最小花费。
    因为题目中说最多经过两次,所以用三进制来表示,这样每一位如果没有经过的时候就为0,经过一次就为1,经过两次就为2.
    最后的答案就是dp[sta][j]中的最小值,其中sta为每个位上的数字至少为1的所有状态。j为1~n.
    要注意一下有可能会有重边,在初始化地图的时候,需要更新a点到b点的最小花费,因为这个错了好几次。
    三进制判断的时候写的有点搓,时间还是比较长。
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <string>
     5 #include <cmath>
     6 #include <vector>
     7 #include <algorithm>
     8 using namespace std;
     9 #define INF 0x3f3f3f
    10 int n, m;
    11 int mp[11][11], dp[60000][11];
    12 int fun(int pos){
    13     return int(pow(3.0, pos));
    14 }
    15 int main(){
    16     while(scanf("%d%d", &n, &m) != EOF){
    17         int a, b, c;
    18         for(int i = 1; i <= n; i++){
    19             for(int j = 1; j <= n; j++){
    20                 if(i == j) mp[i][j] = 0;
    21                 else mp[i][j] = -1;
    22             }
    23         }
    24         for(int i = 1; i <= m; i++){
    25             scanf("%d%d%d", &a, &b, &c); //注意重边。 
    26             if(mp[a][b] == -1) mp[a][b] = mp[b][a] = c;
    27             else mp[a][b] = mp[b][a] = min(mp[a][b], c);
    28         }
    29         for(int i = 0; i < (fun(n)); i++){ 
    30             for(int j = 1; j <= n; j++) dp[i][j] = -1;
    31         } 
    32         for(int pos = 1; pos <= n; pos++) dp[fun(pos-1)][pos] = 0;
    33         
    34         for(int i = 0; i < (fun(n)); i++){
    35             for(int j = 1; j <= n; j++){
    36                 if(dp[i][j] == -1) continue;
    37                 for(int k = 1; k <= n; k++){
    38                     if(mp[j][k] == -1) continue; //如果不连通 
    39                     int tpos = i;
    40                     for(int ii = 1; ii < k; ii++) tpos /= 3;
    41                     tpos = tpos%3; //找到那一位。
    42                     if(tpos == 2) continue;  //这个点已经走了两次了,不能再经过了 
    43                     if(dp[i+fun(k-1)][k] == -1) dp[i+fun(k-1)][k] = dp[i][j] + mp[j][k];
    44                     if(dp[i+fun(k-1)][k] >= dp[i][j] + mp[j][k]) dp[i+fun(k-1)][k] = dp[i][j] + mp[j][k];
    45                 }
    46             }
    47         }
    48         int sum = 0;
    49         for(int i = 0; i < n; i++) sum += int(pow(3.0, i));
    50         int Min = INF;
    51         //sum是每个位上正好为1的状态,从sum开始循环。 
    52         for(int i = sum; i < fun(n); i++){
    53             for(int j = 1; j <= n; j++){
    54                  bool flag = true;
    55                 int temp = i, r;
    56                 while(temp){
    57                     r = temp%3;
    58                     if(r == 0){
    59                         flag = false; break;
    60                     }
    61                     temp /= 3;
    62                 }
    63                 if(flag == false) continue; //判断是否有位上为0,这样的状态是不满足条件的。 
    64                 if(dp[i][j] <= Min && dp[i][j] != -1) Min = dp[i][j];
    65             }
    66         }
    67         printf("%d
    ",Min == INF?-1:Min);
    68     }
    69     return 0;
    70 }
     
  • 相关阅读:
    冒泡 选择 二分法 算法 排序算法
    VUE -->html
    tlplayer for wince 版本正式商用
    XBMC 最新版本错误
    libvlc 双击,鼠标事件消息响应
    windows平台下VLC2.0.5编译
    Fedora 17下交叉编译vlc-2.0.6-win32小记
    wzplayer for ios 针对(mms)优化版本V1.0
    wzplayer2 for windows ActiveX 试用地址
    wzplayer,tlplayer支持ActiveX
  • 原文地址:https://www.cnblogs.com/titicia/p/4354830.html
Copyright © 2011-2022 走看看