HDU4281:Judges' response (mTSP问题)(01背包 状态压缩 DP)

题意:输入n,m,表示有n个地点,m为最大的花费。接着输入n个地点的坐标x,y,起点为第一个地点。还有n个地点的花费。第一问求,每个人有m个钱,求访问完n个点至少需要多少个人。  第二问是可以有任意多个人,求从起点出发遍历n个点后再回到起点的最少距离。

分析:第一问可以状态压缩后,进行01背包。第二问先找到一个人遍历(1~n)个点再回到起点的位置的最短距离,然后把一个人到达n个点的距离进行分解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include<cmath>

using namespace std;

const int maxn = 20;
const int oo = 1<<30;

int x[maxn], y[maxn], c[maxn];
int ok[1<<17], dis[20][20];
int best[1<<17], tem[20][1<<17];
int sta[1<<17], len;

void Init(int n)
{
    int End = (1<<n);
    for(int i = 0; i<End; i++)
        best[i] = oo;
    for(int i = 0; i<n; i++)
    {
        for(int j = 0; j<End; j++)
            tem[i][j] = oo;
    }
    tem[0][1] = 0;
}

int Judge(int state, int n, int m)
{
    int sum = 0;
    for(int i=0; i<n; i++)
        if(state&(1<<i))
            sum+=c[i];
    return sum<=m;
}
int cal(int i,int j)
{
    return ceil(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
}

int DP(int n)
{
    int dp[1<<17];
    fill(dp, dp+(1<<n), oo);
    int state = (1<<n)-1;
    dp[0] = 0;
    for(int i=0; i<len; i++)
    {
        for(int j=state; j>=0; j--)
        {
            if(dp[j]!=oo&&!(sta[i]&j))
                dp[sta[i]+j]=min(dp[sta[i]+j], dp[j]+1);

        }
    }
    return dp[state];
}

int Tsp(int n)
{
    int state = (1<<n)-1;
    for(int i=0; i<=state; i++)
    {
        if(ok[i])
        {
            for(int j=0; j<n; j++)
            {
                if(i&(1<<j))
                {
                    best[i] = min(best[i], tem[j][i]+dis[j][0]);
                    for(int k=0; k<n; k++)
                    {
                        if(!(1&(1<<k)))
                        {
                            tem[k][i|(1<<k)]=min(tem[k][i|(1<<k)], tem[j][i]+dis[j][k]);
                        }
                    }
                }
            }
        }
    }
    for(int i=1; i<=state; i++)
    {
        if(i&1)
        {
            for(int j=i&(i-1); j; j=i&(j-1))
            {
                best[i] = min(best[i], best[(i-j)|1]+best[j]);
            }
        }
    }
    return best[state];
}

int main()
{
    int n, m;
    while(~scanf("%d %d", &n, &m))
    {
        for(int i=0; i<n; i++)
            scanf("%d %d", &x[i], &y[i]);
        for(int i=0; i<n; i++)
            scanf("%d", &c[i]);
        len =0;
        for(int s=0; s<(1<<n); s++)
        {
            ok[s] = Judge(s, n, m);
            if(ok[s])
                sta[len++] = s;
        }
        int ans = DP(n);
        Init(n);
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                dis[i][j] = cal(i, j);
            }
        }
        if(ans == oo)
        {
            puts("-1 -1");
            continue;
        }
        printf("%d %d
", ans, Tsp(n));

    }

    return 0;
}
原文地址:https://www.cnblogs.com/mengzhong/p/5473234.html