UVa 10123 - No Tipping

題目:在一個有兩個支點的槓桿上(支點在-1.5,+1.5),已知桿長和質量,以及上面的重物,

            問是否存在一個順序可以把所有的物品都拿下來,並且不打破平衡。

分析:狀態壓縮、記憶化搜索。數據較小,利用位表示選取狀態,每次兩個支點分別判斷平衡即可。

說明:注意開始時的平衡狀態,dp也可以╮(╯▽╰)╭。

#include <cstdio>
#include <cstring>

int states[1<<20], front[1<<20], space[20], weight[20];

double balance(int n, int select, double support)
{
	double left = 0, right = 0;
	for (int i = 0; i < n; ++ i) 
		if ((1<<i)&select) {
			if (space[i] < support) {
				left += weight[i]*(support-space[i]);
			}else {
				right += weight[i]*(space[i]-support);
			}
		}
	return left - right;
}

int test(int n, int select, double w)
{
	return (balance(n, select, -1.5)-w <= 0)&&(balance(n, select, 1.5)+w >= 0);
}

int save[20];
int dfs(int n, int d, int state, double w)
{
	if (!states[state]) {
		states[state] = 1;
	}else {
		return 0;
	}
	if (!state) {
		for (int i = 0; i < n; ++ i)
			printf("%d %d\n",space[save[i]], weight[save[i]]);
		return 1;
	}
	for (int i = 0; i < n; ++ i) {
		if ((state&(1<<i)) && test(n, state-(1<<i), w)) {
			save[d] = i;
		  	if (dfs(n, d+1, state-(1<<i), w))
				return 1;
		}
	}
	return 0;
}

int main()
{
	int l, m, n, cases = 1;
	while (~scanf("%d%d%d",&l,&m,&n) && l+m+n) {
		for (int i = 0; i < n; ++ i)
			scanf("%d%d",&space[i],&weight[i]);
		
		printf("Case %d:\n",cases ++);
		memset(states, 0, sizeof(states));
		if (test(n, (1<<n)-1, 0.75*m) && !dfs(n, 0, (1<<n)-1, 0.75*m))
			puts("Impossible");
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值