1. 程式人生 > >TSP問題 動態規劃實現

TSP問題 動態規劃實現

貨郎擔問題(TSP)。有n個城市,兩兩之間均有路直接連線,求一條經過每個城市一次且僅一次,最後返回起點的最短路線。

這是劉汝佳書上的一道題,他給出了思路,我實現了一下。

用動態規劃解決,可以假設從0點出發,然後回到0點。那麼用 f(i,S)表示現在處在i點,要去訪問剩餘的在集合S中的點,集合S可以用二進位制數st。

那麼狀態轉移方程就是:f(i,S)=min{d(j,S-{j})+dist(i,j)|j屬於S}

程式碼:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int dis[12][12],f[1<<12][12],pos[1<<12][12];
//f[st][i]表示處在i點,還要訪問集合st的點各一次後返回0點的最短路
int main()
{
    int n;
   // freopen("f.txt","r",stdin);
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                scanf("%d",&dis[i][j]);
                //dis[i][j]=s[i][j];
            }
        }
        int b=1<<(n-1);
        memset(f,-1,sizeof(f));
        for(int i=0;i<n;i++) //邊界處理
            f[0][i]=dis[i][0]; //st是空集,表示都已經訪問完了,剩餘路程就是從i點回到0點
        for(int st=1;st<b-1;st++){
            for(int i=1;i<n;i++){
                if(st&(1<<(i-1)))continue; //如果i點在集合中沒訪問,那麼f[st][i]這個狀態就不成立
                int minn=INF;
                for(int j=1;j<n;j++){  //列舉從i點要去j點
                    if(st&(1<<(j-1))){  //保證j點在集合st中
                        int tmp=dis[i][j]+f[st^(1<<(j-1))][j]; //把j點從st集合中去掉
                        if(tmp<minn){  //更新最小值
                            minn=tmp;
                            f[st][i]=tmp;
                            pos[st][i]=j;  //記錄路徑
                        }
                    }
                }
            }
        }
        int minn=INF;
        for(int k=1;k<n;k++){
            int tmp=f[(b-1)^(1<<(k-1))][k]+dis[0][k];
            if(tmp<minn)
                minn=tmp,f[b-1][0]=tmp,pos[b-1][0]=k;;
        }
        printf("%d\n",f[b-1][0]);

//        printf("0\n");  //列印路徑
//        for(int st=b-1,next=0;st;){
//            next=pos[st][next];
//            printf("%d\n",next);
//            st=st^(1<<(next-1));
//        }
//        printf("0\n");
    }
    return 0;
}