例题7-7 天平难题(Mobile Computing, ACM/ICPC Tokyo 2005, UVa1354)

思路:由于每种天平都对应着一种二叉树,所以枚举出所有的二叉树。
关键在于如何去枚举这些情况呢?
想了好久。。。还是实现不出来。。orz。。参考了lls的代码。。受益匪浅。。
1. 枚举子集:for (int left = (subset - 1)⊂ left; left = (left - 1)&subset)
2. 求补集:int right = left^subset
3. 自底向上求解出了最大长度。。(后序求解?类似求树高?)
4. 求取有限制的最值。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define CLEAR(a, b) memset(a, b, sizeof(a))
#define IN() freopen("in.txt", "r", stdin)
#define OUT() freopen("out.txt", "w", stdout)
#define LL long long
#define maxn 7
#define maxm 100005
#define mod 1000000007
#define INF 1000000007
#define eps 1e-5
#define PI 3.1415926535898
#define N 26
using namespace std;
//-------------------------CHC------------------------------//
double s;
int n;
double w[maxn], sum[1 << maxn];
bool vis[1 << maxn];
struct Node {
	double l, r;
	Node(double l = 0, double r = 0) :l(l), r(r) { }
};
vector v[1 << maxn];

void dfs(int subset) {
	if (vis[subset]) return;	//回溯法
	vis[subset] = true;
	if (((subset - 1) & subset) == 0) {
		v[subset].push_back(Node());
		return;
	}
	for (int left = (subset - 1)⊂ left; left = (left - 1)&subset) {
		int right = left^subset;
		double dr = sum[left] / sum[subset], dl = sum[right] / sum[subset];
		dfs(left);
		dfs(right);
		for (int i = 0; i < v[left].size(); ++i)
			for (int j = 0; j < v[right].size(); ++j) {
				Node cur;
				cur.l = max(v[left][i].l + dl, v[right][j].l - dr);	//
				cur.r = max(v[right][j].r + dr, v[left][i].r - dl);	//
				if (cur.l + cur.r < s) v[subset].push_back(cur);
			}
	}
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		CLEAR(sum, 0);
		CLEAR(vis, 0);
		scanf("%lf%d", &s, &n);
		for (int i = 0; i < n; ++i)
			scanf("%lf", &w[i]);
		for (int i = 1; i < (1 << n); ++i) {	//预处理了各个集合的总重量
			v[i].clear();
			for (int j = 0; j < n; ++j)
				if ((1 << j) & (i))
					sum[i] += w[j];
		}
		int root = (1 << n) - 1;
		dfs(root);
		double ans = -1;
		for (int i = 0; i < v[root].size(); ++i)
			ans = max(ans, v[root][i].l + v[root][i].r);
		printf("%.10lf\n", ans);
	}
	return 0;
}

你可能感兴趣的:(回溯法,紫书,第七章,例题)