HDU4281:Judges' response(mTSP问题)

Problem Description
  The contest is running and the judges is busy watching the progress of the contest. Suddenly, N - 1 (N <= 16) contestants hand up their hand at the same time. The judges should go to answer the contestants' question one by one. The judges already foresee that answering contest i's question would cost Ci minutes. In order to serve all the contestant, each judges is assigned to serve some subset of the contestants. As the judges have limited patience, each one of them can serve the contestants for no more than M minutes.
  You are asked to solve two problems:
  1. At least how many judges should be sent so that they can serve all the contestants? (Because the judges have limited patience, each one of them cannot serve too many contestants.)
  2. If there are infinite number of judges, how to assign the route for each judge so that the sum of their walking time is minimized? Each contestant i is reside in place (xi, yi), the judges are in place (x1, y1). Assuming the walking speed of the judge is 1.
 

Input
  There are several test cases, Each case begin with two integer N, M(with the meaning in the above context, 2 <= N <= 16, 0 <= M <= 100000).
  Then N lines follow and line i will contain two numbers x, y(0 <= x, y <= 1000), indicating the coordinate of place i.
  Then another N lines follow and line i will contain numbers Ci(0 <= Ci <= 1000), indicating the time to solve contestant i's question. C1 will 0 as place 1 is for the judges.
  
  The distance between place i and place j is defined as ceil(sqrt((xi - xj) ^ 2 + (yi - yj) ^ 2)). (ceil means rounding the number up, e.g. ceil(4.1) = 5)
 

Output
  For each case, output two numbers. The first is the minimum number of judges for question 1. The second is the minimum sum of walking time for question 2.
  If it's impossible to serve all the contestants, please output -1 -1 instead.
 

Sample Input
   
   
   
   
3 3 0 0 0 3 0 1 0 1 2 3 2 0 0 0 3 0 1 0 1 2 3 1 0 0 0 3 0 1 0 1 2    16 35 30 40 37 52 49 49 52 64 31 62 52 33 42 41 52 41 57 58 62 42 42 57 27 68 43 67 58 48 58 27 37 69 0 19 30 16 23 11 31 15 28 8 8 7 14 6 19 11
 

Sample Output
   
   
   
   
1 6 2 8 -1 -1 8 467
题意:有n道题,每道题在二维平面内的不同位置且给出每道题的坐标,同时给出处理每道题所需的时间p,现在已知裁判的耐心有限,之会花费m个单位时间去做事,做完后回到起始点。
现在的要求是,我要多少个裁判才能对每个问题都处理完,并且同一道题不能有两个裁判进行处理,并求出总路径最小的值。
思路:一开始对于怎么求最小路径花费没有什么想法,看看别人的做法才知道是多旅行商问题,以前没有看过这样的题目,学习了。
首先只有16个题目,很容易想到对其状态进行压缩,那么我们先来处理第一个问题:应该选几个裁判?
首先dp[i](i:1~1<<n-1)表示这个状态下的最小裁判,那么我们只需要来个背包就能得出最终状态下最少需要的裁判
第一个问题还是很容易解决的
那么第二个问题:这些裁判走过的最小路径到底是多少呢?
这就是多旅行商问题了
首先best[i]表示这个状态下且回到起始点的最小花费,tem[j][i]表示在i状态下最后停留在j点时候的最小花费
那么通过三重循环的枚举,我们可以求得所有一个裁判走路径为i的所有最优解
然后我们再来循环枚举算出多个裁判的情况下对应的最后状态下的最优解
也就是这个循环
for(i = 1; i<end; i++)
    {
        if(i&1)
        {
            for(j = i&(i-1); j; j=i&(j-1))
                best[i] = min(best[i],best[(i-j)|1]+best[j]);
        }
    }

那么我们可以看到,对于每个i,我们得到x=(i-j)|1,y=j,如果用二进制去看,可以发现由于其低位是起始点,距离是0可以忽略,其他位对于x与y来说是互异的,也就是说我们通过这个循环可以枚举出对于i而言,所有可以组成i的两种裁判路径的和与其本身的值的最小值
而i必须是奇数,这样才是从原点开始的状态


<pre name="code" class="cpp">#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int inf = 1<<30;
struct node
{
    int x,y,p;
} a[20];

int n,m,maxn;
int dis[20][20];
int best[1<<16],tem[20][1<<16];
int state[1<<16],ok[1<<16],len,end;

int cal(int i,int j)//求路径
{
    return ceil(sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)));
}

int check(int s)//检查这种状态是否可行
{
    int i,sum = 0;
    for(i = 0; i<n; i++)
    {
        if(s&(1<<i))
            sum+=a[i].p;
    }
    return sum<=m;
}
void init()//初始化
{
    int i,j,k;
    for(i = 0; i<end; i++)
        best[i] = inf;
    for(i = 0; i<n; i++)
    {
        for(j = 0; j<end; j++)
            tem[i][j] = inf;
    }
    tem[0][1] = 0;
}
int cnt()//背包求裁判个数
{
    int i,j;
    int dp[1<<16];
    for(i = 1; i<end; i++)
        dp[i]=inf;
    dp[0] = 0;
    for(i = 0; i<len; i++)
    {
        for(j = end-1; j>=0; j--)
        {
            if(dp[j]==inf) continue;
            if(state[i]&j) continue;
            dp[state[i]+j]=min(dp[state[i]+j],dp[j]+1);
        }
    }
    return dp[end-1]==inf?-1:dp[end-1];
}

int TSP()
{
    int i,j,k;
    for(i = 0; i<end; i++)//求出各种路径一种裁判的消费
    {
        if(ok[i])
        {
            for(j = 0; j<n; j++)
            {
                if(i&(1<<j))
                {
                    best[i]=min(best[i],tem[j][i]+dis[j][0]);
                    for(k = 0; k<n; k++)
                        if(!(i&(1<<k)))
                            tem[k][i|(1<<k)] = min(tem[k][i|(1<<k)],tem[j][i]+dis[j][k]);
                }
            }
        }
    }
    for(i = 1; i<end; i++)//多裁判消费
    {
        if(i&1)
        {
            for(j = i&(i-1); j; j=i&(j-1))
                best[i] = min(best[i],best[(i-j)|1]+best[j]);
        }
    }
    return best[end-1];
}

int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        len = 0;
        end = 1<<n;
        for(i = 0; i<n; i++)
            scanf("%d%d",&a[i].x,&a[i].y);
        for(i = 0; i<n; i++)
            scanf("%d",&a[i].p);
        for(i = 0; i<end; i++)
        {
            ok[i]=check(i);
            if(ok[i])
                state[len++] = i;
        }
        for(i = 0; i<n; i++)
        {
            for(j = 0; j<n; j++)
                dis[i][j] = cal(i,j);
        }
        init();
        int flag = cnt();
        if(flag==-1)
        {
            printf("-1 -1\n");
            continue;
        }
        printf("%d %d\n",flag,TSP());
    }

    return 0;
}




你可能感兴趣的:(dp)