1. 程式人生 > >搜尋進階-----J

搜尋進階-----J

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

因為題好讀才做的,寫了一發爆搜,tle了,找了半天剪枝方法,找不到,之後看的題解,沒想到是狀壓dp,一直想的是怎麼搜 這樣的狀態壓縮,然後dp,把所有狀態和情況都判了一遍,還不會超時。。。 1>dp[i][j]代表當走到第i個城市所處的j狀態所需的最小花費 2>轉移方程dp[k][state + fac[k]] = min(dp[k][state + fac[k]],dp[j][state] + mp[j][k]); 當走到第k個城市所處的狀態是state + fac[k],這個狀態是由第j個城市所處狀態轉移來的,因為j與k之間有邊 3>邊界初始化時,是把每個城市作為開端時所產生的初始狀態賦為0,像2000000,則將dp[6][2000000的十進位制數] = 0; 4>找結束時,都走了一遍之後,num == n為結束條件,停在哪個城市最短不知道,都需要比較一次

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
#define pb push_back
#define fi first
#define se second
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 5;

int dp[15][N];
int fac[15];
int n,m;
int mp[15][15];

int change(int a[],int ans)
{
    int k = 0;
    int sum = 0;
    while(ans != 0)
    {
        a[k++] = ans % 3;
        ans /= 3;
        if(a[k - 1] > 0){
            sum++;
        }
    }
    return sum;
}

int main()
{
    fac[0] = 1;
    for(int i = 1;i <= 10;++i){
        fac[i] = fac[i - 1] * 3;
    }
    while(~scanf("%d %d",&n,&m))
    {
        memset(dp,inf,sizeof(dp));
        memset(mp,-1,sizeof(mp));
        for(int i = 0;i < m;++i)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            a--;b--;
            if(mp[a][b] == -1){
                mp[a][b] = c;mp[b][a] = c;
            }else{
                mp[a][b] = mp[b][a] = min(mp[a][b],c);
            }
        }
        int ans = inf;
        for(int i = 1;i < fac[n];++i)
        {
            int a[15];
            memset(a,0,sizeof(a));
            int num = change(a,i);
            for(int j = 0;j < n;++j)
            {
                if(a[j]){
                    if(num == 1) dp[j][i] = 0;
                    if(num == n){
                        ans = min(ans,dp[j][i]);
                    }
                    for(int k = 0;k < n;++k)
                    {
                        if(k != j && a[k] < 2 && mp[j][k] != -1){
                            dp[k][i + fac[k]] = min(dp[k][i + fac[k]],dp[j][i] + mp[j][k]);
                        }
                    }
                }
            }
        }
        if(ans == inf){
            printf("-1\n");
        }else{
            printf("%d\n",ans);
        }
    }
    return 0;
}