poj3311(状压dp)

 

题目连接:http://poj.org/problem?id=3311

题意:一个送披萨的,每次送外卖不超过10个地方,给你这些地方之间的时间,求送完外卖回到店里的总时间最小。

分析:跑一遍Floyd求出两两之间的最短距离,然后就是一个裸TSP问题了。

dp[state][i]表示在state状态下(state的二进制1表示经过的点)当前处于i点的的最少时间。

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-9

#define N 100010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

using namespace std;

int dis[20][20],n;

int dp[1200][15];

void floyd()

{

    for(int k=0;k<=n;k++)

      for(int i=0;i<=n;i++)

        for(int j=0;j<=n;j++)

        if(dis[i][j]>dis[i][k]+dis[k][j])

        dis[i][j]=dis[i][k]+dis[k][j];

}

int main()

{

    while(scanf("%d",&n)&&n)

    {

        for(int i=0;i<=n;i++)

            for(int j=0;j<=n;j++)

            scanf("%d",&dis[i][j]);

        floyd();

        for(int s=0;s<(1<<n);s++)

        for(int i=1;i<=n;i++)

        {

            if(s&(1<<(i-1)))//经过i点

            {

                if(s==(1<<(i-1)))dp[s][i]=dis[0][i];

                else

                {

                    dp[s][i]=inf;

                    for(int j=1;j<=n;j++)

                    {

                        if((s&(1<<(j-1)))&&i!=j)//经过j点

                            dp[s][i]=min(dp[s][i],dp[s^(1<<(i-1))][j]+dis[j][i]);//松弛

                    }

                }

            }

        }

        int ans=inf;

        for(int i=1;i<=n;i++)

            if(dp[(1<<n)-1][i]+dis[i][0]<ans)

            ans=dp[(1<<n)-1][i]+dis[i][0];

        printf("%d\n",ans);

    }

}
View Code

 

你可能感兴趣的:(poj)