**HDU 4281 - Judges' response(DP`背包+TSP)

来源:互联网 发布:84cs域名升级访问升级 编辑:程序博客网 时间:2024/06/07 01:45

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4281

题意:

给出n个题目的坐标和花费的时间,每个裁判解决题目的时间为m,每个题目只能让一个裁判解决。

求出1.最少派出多少裁判才能将所有的题目解决。2.不限裁判数量,解决所有的问题的最少路径。

思路:

解决问题一:

将2^n种的地点选择 看成 2^n种物品,物品的权值为所选择的物品的总权值,将合法的总权值(<= m)存起来,物品总数为tot。dp【i】表示权值为i时最少的裁判数。

dp[i] = min(dp[i], dp[j]+1)..

解决问题2:

这是一个多旅行商问题。

思路是将mtsp转化成tsp,然后将各个tsp合并成答案。

先预处理np[i]: 表示一个裁判走的集合为i德尔所有地点且回到原点的最少权值和。

np[i] = min(np[i], np[j|1] + np[(i-j)|1]) ..

AC.

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>using namespace std;const int inf = 0x3f3f3f3f;const int maxn = 17;int n, m;int x[maxn], y[maxn], v[maxn];int tot, state[1<<maxn], sta[1<<maxn];int dis[maxn][maxn];bool ok(int x){    int sum = 0;    for(int i = 0; i < n; ++i) {        if(x & (1<<i)) sum += v[i];    }    return sum <= m;}int cal(int a, int b){    return ceil(sqrt((x[a]-x[b])*(x[a]-x[b]) + (y[a]-y[b])*(y[a]-y[b])));}int cal_dis(){    for(int i = 0; i < n; ++i) {        for(int j = i+1; j < n; ++j) {            dis[i][j] = dis[j][i] = cal(i, j);        }    }}int dp[1<<maxn];int solve1(){    fill(dp, dp+(1<<maxn)+1, inf);    dp[0] = 0;    for(int i = 0; i < tot; ++i) {        for(int j = (1<<n)-1; j >= 0; --j) {            if(dp[j] == inf) continue;            int c = j + state[i];            if(c != (j | state[i])) continue;            dp[c] = min(dp[c], dp[j] + 1);        }    }    return dp[(1<<n)-1] == inf? -1: dp[(1<<n)-1];}int cost[maxn][(1<<maxn)], np[(1<<maxn)];int solve2(){    for(int i = 0; i < n; ++i) {        fill(cost[i], cost[i] + (1<<n), inf);    }    cost[0][1] = 0;    fill(np, np+(1<<n), inf);    for(int i = 1; i < (1<<n); ++i) {        if(sta[i]) {            for(int j = 0; j < n; ++j) {                if(i & (1<<j)) {                    np[i] = min(np[i], cost[j][i] + dis[j][0]);                }                for(int k = 0; k < n; ++k) {                    if((i & (1<<k)) == 0) {                        cost[k][i|(1<<k)] = min(cost[k][i|(1<<k)], cost[j][i] + dis[j][k]);                    }                }            }        }    }    for(int i = 1; i < (1<<n); ++i) {        if(i&1) {            for(int j = (i-1)&i; j; j = (j-1)&i) { //j为i的二进制子集。               // printf("i = %d, j = %d\n", i, j);                np[i] = min(np[i], np[j|1] + np[(i-j)|1]);            }        }    }    return np[(1<<n)-1] == inf? -1: np[(1<<n)-1];}int main(){    freopen("in", "r", stdin);    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", &v[i]);        }        tot = 0;        for(int i = (1<<n); i >= 0; --i) {            sta[i] = ok(i);            if(sta[i]) state[tot++] = i;        }        memset(dis, 0, sizeof(dis));        cal_dis();        int ans1 = solve1();        int ans2 = solve2();        printf("%d %d\n", ans1, ans2);    }    return 0;}


0 0
原创粉丝点击