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.
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)
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.
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; }