您的位置:首页 > 其它

HDU 4281 Judges' response 状态压缩 01背包 MTSP

2015-02-03 14:31 369 查看
题意:比赛上,有N个选手提出了问题,解决每个选手的问题需要的时间是Ci。现在每个裁判至多能为选手解答时间长为M的问题。至少需要几个裁判才能解决所有的选手的问题。

同时,给出每个选手的位置坐标xi,yi.希望所有裁判从起始点出发,解决完所有问题,再回到起始点,所走的距离和最小。

思路:其实这两问的答案是基本没有关系。唯一的关系,就是如果第一问没有解的话,第二问也是没有解的。所以,我们分别讨论这两个问题。

对于第一问,我们注意到,N很小,这是指数复杂度的一个标志。我们的目标是完成所有选手的问题,而这个可以利用状态压缩作为最终的目标。

因为我们要求至少需要多少个裁判,所以要先预处理一个裁判,可以完成那些选手的问题。

之后,就是状态压缩形式的01背包了。

对于第二问:如果问题简化为1个裁判的话,就是个旅行商问题,即用最短的距离访问所有的点并返回。要是裁判多了的话,其实就是个多旅行商问题(MTSP)。

对于MTSP问题,我们首先求出1个旅行商的TSP问题,这个可以用状态压缩的DP得到。

然后就是把单个旅行商合成多个旅行商,其实这也类似第一问的状态压缩形式的01背包。

注意:在TSP的问题中,要注意初始化,将起始的城市初始化为0.

代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
#include <cmath>
#include <vector>

using namespace std;

const int MAX = 17;

int x[MAX],y[MAX],dis[MAX][MAX];
int c[MAX],N,M;
int dp[1<<MAX],dp2[1<<MAX][20],va[1<<MAX],vec[1<<MAX],sz,all;

int judge(int s)
{
int sum = 0;
for(int i = 0; i < N; ++i)
if((s>>i) & 1)
sum += c[i];
return va[s] = (sum <= M);
}

void pre_work()
{
for(int i = 0; i < N; ++i){
for(int j = 0; j < i; ++j){
double dx = x[i] - x[j];
double dy = y[i] - y[j];
dis[i][j] = dis[j][i] = ceil(sqrt(dx*dx+dy*dy));
}
dis[i][i] = 0;
}
sz = 0;
all = (1<<N) - 1;
for(int i = 0; i <= all; ++i)
if(judge(i))
vec[sz++] = i;
}

int solve1()
{
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for(int i = 0; i < sz; ++i){
for(int j = all; j >= 0; --j){
int s = j + vec[i];
if(s != (j | vec[i])) continue;
dp[s] = min(dp[s],dp[j]+1);
}
}
return dp[all];
}

int solve2()
{
memset(dp2,0x3f,sizeof(dp2));
memset(dp,0x3f,sizeof(dp));
dp2[1][0] = 0;
for(int s = 0; s <= all; ++s) if(va[s])
for(int i = 0; i < N; ++i) if((s>>i)&1){
dp[s] = min(dp[s],dp2[s][i] + dis[i][0]);
for(int j = 0; j < N; ++j) if(!((s>>j)&1))
dp2[s|(1<<j)][j] = min(dp2[s|(1<<j)][j],dp2[s][i]+dis[i][j]);
}

for(int s = 0; s <= all; ++s) if(s&1)
for(int j = (s-1) & s;j; j = (j-1) & s)
dp[s] = min(dp[s],dp[j|1] + dp[(s-j) | 1]);
return dp[all];
}

int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d%d",&N,&M) != EOF){
for(int i = 0; i < N; ++i)
scanf("%d%d",&x[i],&y[i]);
for(int i = 0; i < N; ++i)
scanf("%d",&c[i]);
pre_work();
int ans1 = solve1();
if(ans1 == 0x3f3f3f3f)
puts("-1 -1");
else
printf("%d %d\n",ans1,solve2());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: