[BZOJ2073][POI2004]PRZ

[BZOJ2073][POI2004]PRZ

试题描述

一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时只能分批过,当一组全部过去时,下一组才能接着过. 队伍里每个人过桥都需要特定的时间,当一批队员过桥时时间应该算走得最慢的那一个,每个人也有特定的重量,我们想知道如何分批过桥能使总时间最少.

输入

第一行两个数: w – 桥能承受的最大重量(100 <= w <= 400) 和 n – 队员总数(1 <= n <= 16). 接下来n 行每行两个数分别表示: t – 该队员过桥所需时间(1 <= t <= 50) 和 w – 该队员的重量(10 <= w <= 100).

输出

输出一个数表示最少的过桥时间.

输入示例

100 3
24 60
10 40
18 50

输出示例

42

数据规模及约定

见“输入

题解

设 f(S) 表示让 S 集合的人过桥所需要的最短总时间。转移的时候枚举子集即可。开始时预处理一下每个集合的重量总和与最大时间,这样状态数乘转移数就变成 3n 的了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
	return x * f;
}

#define maxn 20
#define maxs 65536
#define oo 2147483647

int W, n, tim[maxn], wei[maxn], sumw[maxs], maxt[maxs], f[maxs];

int dp(int S) {
	if(f[S] < oo) return f[S];
	if(sumw[S] <= W) return f[S] = maxt[S];
	for(int tS = S - 1 & S; tS; tS = tS - 1 & S)
		if(dp(tS) < oo && dp(S^tS) < oo) f[S] = min(f[S], dp(tS) + dp(S^tS));
	return f[S];
}

int main() {
	W = read(); n = read();
	for(int i = 0; i < n; i++) tim[i] = read(), wei[i] = read();
	
	int all = (1 << n) - 1;
	for(int S = 0; S <= all; S++)
		for(int i = 0; i < n; i++) if(S >> i & 1)
			maxt[S] = max(maxt[S], tim[i]), sumw[S] += wei[i];
	for(int S = 0; S <= all; S++) f[S] = oo;
	
	printf("%d\n", dp(all));
	
	return 0;
}

 

posted @ 2017-06-03 21:36  xjr01  阅读(205)  评论(0编辑  收藏  举报