hdu 5418 (狀壓dp)

Victor and World

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)
Total Submission(s): 2238    Accepted Submission(s): 1037


 

Problem Description

After trying hard for many years, Victor has finally received a pilot license. To have a celebration, he intends to buy himself an airplane and fly around the world. There are n countries on the earth, which are numbered from 1 to n. They are connected by m undirected flights, detailedly the i-th flight connects the ui-th and the vi-th country, and it will cost Victor's airplane wi L fuel if Victor flies through it. And it is possible for him to fly to every country from the first country.

Victor now is at the country whose number is 1, he wants to know the minimal amount of fuel for him to visit every country at least once and finally return to the first country.

 

 

Input

The first line of the input contains an integer T, denoting the number of test cases.
In every test case, there are two integers n and m in the first line, denoting the number of the countries and the number of the flights.

Then there are m lines, each line contains three integers ui, vi and wi, describing a flight.

1≤T≤20.

1≤n≤16.

1≤m≤100000.

1≤wi≤100.

1≤ui,vi≤n.

 

 

Output

Your program should print T lines : the i-th of these should contain a single integer, denoting the minimal amount of fuel for Victor to finish the travel.

 

 

Sample Input


 

1 3 2 1 2 2 1 3 3

 

 

Sample Output


 

10

 

 

Source

BestCoder Round #52 (div.2)

 

 

Recommend

hujie   |   We have carefully selected several similar problems for you:  6645 6644 6643 6642 6641 

 

題目給出的數據 n < 16。很明顯不要我們用太複雜的圖論求解,而且正好開的下二維數組,可以用狀壓dp了

dp【s】【i】(當前經過了s,在點i 所用的權值)中 s是個集合,i表示當前所在的點。

s用的是十進制來表示的二進制。如:s = 3 = 101 表示當前集合中點1和點3已經經過,點2沒有經過。

還有要注意的就是本題的TSP是可以跑回路的,一個點可以經過多次。我們在處理之前跑一便最短路(Floyd)。

 

#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <bitset>
#define  LL long long
#define  ULL unsigned long long
#define mod 10007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
#define maxn 50
using namespace std;
//const int maxn = 50;
int mp[maxn][maxn];
int n;
int dp[(1 << 16) + 10][maxn];
void init()
{
    fill(mp[0],mp[0] + maxn * maxn,INF);
    fill(dp[0],dp[0] + (1 << 16) * maxn,INF);
    for(int i = 0; i < maxn; i++) mp[i][i] = 0;
    //fill(mp,mp + 50 * 50,INF);
}
void Floyd()
{
    for(int k = 0; k < n;k++){
      for(int i = 0; i < n;i++){
        for(int j = 0; j < n; j++){
           mp[i][j] = min(mp[i][k] + mp[k][j],mp[i][j]);
        }
      }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
      int m;
      init();
      scanf("%d%d",&n,&m);
      while(m--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        a--,b--;
        if(mp[a][b] > c) mp[a][b] = mp[b][a] = c;
      }

      Floyd();
      dp[1][0] = 0;
      for(int s = 1; s < (1 << n); s++){//考慮所有出現的情況
        for(int i = 0; i < n; i++)//遍歷兩點之間的起點
        if(s & (1 << i)){
            for(int j = 0; j < n; j++){//遍歷終點
              if((s & (1 << j)) == 0){
                dp[s | (1 << j)][j] = min(dp[s | (1 << j)][j],dp[s][i] + mp[i][j]);
              }
            }
        }

      }
      int ans = INF;
      for(int i = 1; i < n; i++){//這一步是回到起點,遍歷所有的點(因爲所有的點都肯能是最後一個點),選一個最小的的邊。
        ans = min(ans,dp[(1 << n) - 1][i] + mp[i][0]);
      }
      if(n == 1) printf("0\n");
      else printf("%d\n",ans);
    }

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章