首页 > 代码库 > poj 3311 状压DP

poj 3311 状压DP

经典TSP变形


学到:1、floyd  O(n^3)处理任意两点的最短路

    2、集合的位表示,我会在最后的总结出写出。注意写代码之前一定设计好位的状态,本题中,第0位到第n位分别代表第i个城市,1是已经走过,0没走过

那么DP方程  :dp[s][i]--当前在城市i,状态为s(s存储的是走过了那些城市)


            3、最后要求形成回路,那么就是min(dp[1<<(n+1)-1][i],dp[0][i])


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)

const int MAXN = 12;
int dis[MAXN][MAXN];
int dp[1<<MAXN][MAXN];
const int INF = 1e9+10;
int n;

void floyd()
{
    rep(k,0,n+1)
        rep(i,0,n+1)
            rep(j,0,n+1)
                dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);

}

int main()
{
    //IN("poj3311.txt");
    int len;
    while(~scanf("%d",&n) && n)
    {
        rep(i,0,n+1)
            rep(j,0,n+1)
                dp[i][j]=dis[i][j]=INF;
        rep(i,0,n+1)
            rep(j,0,n+1)
            {
                scanf("%d",&len);
                dis[i][j]=min(dis[i][j],len);
            }
        floyd();//求出任意两点的距离
        int S=1<<(n+1);
        rep(i,0,S)
            rep(j,0,n+1)
            {
                    dp[i][j]=INF;
            }

        for(int s=0;s<S;s++)//枚举所有的状态
            rep(i,0,n+1)
            {
                if(s&(1<<(i)))
                    {
                        if(s==(1<<i))dp[s][i]=dis[0][i];
                        else
                        rep(j,0,n+1)
                            if(s&(1<<j) && i!=j)
                            {
                                dp[s][i]=min(dp[s^(1<<i)][j]+dis[j][i],dp[s][i]);
                            }
                    }
            }
        int ans=INF;
        for(int i=0;i<n+1;i++)
            ans=min(ans,dp[(S-1)][i]+dis[i][0]);
        printf("%d\n",ans);
    }
    return 0;
}