题目:
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;
}