HDU 4281 (状态压缩+背包+MTSP)

Judges' response

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 741    Accepted Submission(s): 429


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-1个人有问题需要裁判答复、每个人需要Ci的时间、每个裁判最多回答M时间的问题、问最小需要几个裁判。

  第二问:每个人有个位置、所有裁判都在一个位置、问所有裁判回答完问题并回到原点加起来走过的距离最小是多少。

  第一问和第二问是独立的,不一定在最少裁判的基础上来走。

解题:

  第一问就是一个带有状态的01背包。

  第二问是多旅行商问题(MTSP)。

AC代码:

/** @xigua */
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
#include<deque>
#include<queue>
#include<set>
#include<string>
#include<map>
#include<climits>
#define inf LLONG_MAX
#define INF 9e7+5
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 1e2 + 5;
const ll mod = 3e12 + 7;
const db eps = 1e-9;
int n, m, x[maxn], y[maxn], c[maxn];
int dis[maxn][maxn], dp[1<<16];
int sta[1<<16], len, best[1<<16], en[16][1<<16]; //en的第二维代表状态,比如en[j][i]代表在i状态下以j结尾的最小距离
bool xx[1<<16];

int get_dis(int x1, int x2, int y1, int y2) {
    return ceil(sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)));
}

void init() {
    memset(xx, 0, sizeof(xx));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) dis[i][j] = get_dis(x[i], x[j], y[i], y[j]);
    for (int i = 0; i < (1<<n); i++) {
        best[i] = INF;
        dp[i] = INF;
        for (int j = 0; j < n; j++)
            en[j][i] = INF;
    }
    en[0][1] = best[0] = len = dp[0] = 0;
}

bool ok(int x) {//判断当前状态能否由一个裁判回答完
    int sum = 0;
    for (int i = 0; i < n; i++) {
        if (x&(1<<i))
            sum += c[i];
    }
    return m >= sum;
}

void get_sta() {
    for (int i = 0; i < (1<<n); i++) {
        if (ok(i))
            sta[++len] = i, xx[i] = 1;
    }
}

int solve_bag() {
    for (int i = 1; i <= len; i++) {
        for (int j = (1<<n) - 1; j >= 0; j--) {
            if (!(sta[i] & j)) {
                dp[sta[i]|j] = min(dp[sta[i]|j], dp[j] + 1);
            }
        }
    }
    return dp[(1<<n)-1] == INF ? -1 : dp[(1<<n)-1];
}

int solve_dd() {
    for (int i = 0; i < (1<<n); i++) {
        if (xx[i]) {
            for (int j = 0; j < n; j++) {
                if (i&(1<<j)) {
                    best[i] = min(best[i], en[j][i] + dis[j][0]); 
                    for (int k = 0; k < n; k++) {
                        if (!(i&(1<<k))) {
                            en[k][i|(1<<k)] = min(en[k][i|(1<<k)], en[j][i] + dis[j][k]);
                        }
                    }
                }
            }
        }
    }
    for (int i = 1; i < (1<<n); 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|1]);
    return best[(1<<n)-1];
}

void solve() {
    while (cin >> n >> m) {
        for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
        for (int i = 0; i < n; i++) cin >> c[i];
        init();
        get_sta();
        int ans1= solve_bag();
        if (ans1 == -1) cout << "-1 -1\n";
        else cout << ans1 << ' ' << solve_dd() << endl;
    }
}

int main() {
    //cin.sync_with_stdio(false);
    //freopen("tt.txt", "r", stdin);
    //freopen("hh.txt", "w", stdout);
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

  

转载于:https://www.cnblogs.com/ost-xg/p/6223861.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值