TSP hdu 5418

hdu 5418

這道題是到最基礎的狀壓dp,外加一個floyid距離問題(最短距離).

大概題意是有個人從1號位置出發,經過其他n-1個位置又回到1號位置,並且要求其他的地方至少都要走一遍,告訴有m條路徑,每條路徑都有個起點和終點,還有走這條路徑需要的花費,最後求走完所有的地方花費最少是多少?

下邊來看代碼:

#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
int a[18][18],dp[18][1<<18];
const int inf=0x3f3f3f3f;
int n,m;
void floyid()//floyid距離,最短距離的求法
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
}
int  main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int u,v,t;
        for(int i=1;i<=n;i++)//對距離初始化
            {
                for(int j=1;j<=n;j++)
                a[i][j]=(i==j)?0:inf;
            }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&t);
            if(t<a[u][v])a[u][v]=a[v][u]=t;//這裏很容易漏掉,因爲觀察到題目中n和m的範圍才發現,這是個陷阱,1<=n<=16,1<=m<=100000,這裏的m太大了,也就是路勁數出奇的多,假設所有的地點都用上,路徑數最多也就是16*16,不會有10w,所以一定有一些兩點之間的路徑重複給出,所以要取其中最小的哦。。。
        }
        if(n==1){cout<<0<<endl;continue;}
        floyid();
        memset(dp,inf,sizeof dp);
        dp[1][1]=0;
        for(int s=1;s<(1<<n);s++)
        {
            for(int i=1;i<=n;i++)
                    if(s&(1<<i-1))continue;//狀態轉移的時候,需要這個被轉移的地點還沒有走過,如果走過了,那麼直接就是pass掉了
                    else {
                        for(int k=1;k<=n;k++)
                        if(s&(1<<k-1)){//要求中間的節點k一定已經走過了,只有這樣纔可以繼續由這個中間節點到達最後的狀態轉移的i節點
                            dp[i][s|(1<<i-1)]=min(dp[i][s|(1<<i-1)],dp[k][s]+a[k][i]);
                        }
                    }
        }
//        for(int i=1;i<=n;i++)
//        {
//            cout<<i<<":"<<dp[i][(1<<n)-1]<<endl;
//        }
        int minn=inf;
        for(int i=2;i<=n;i++)//這裏是算加上第i個地點回到1的距離,最後取最小的
            minn=min(minn,dp[i][(1<<n)-1]+a[i][1]);
        printf("%d\n",minn);
    }
}

發佈了52 篇原創文章 · 獲贊 15 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章