UVA - 10123 No Tipping 剪枝+dfs

题目大意:给出一个有两个支点的杆子,杆子的长为L,重为W,上面有N个木块,求如果把木块拿走才能避免天平失去平衡

解题思路:1.将拿木快换成放木块,然后逆序输出就是拿走木块的顺序了

                  2.将没快木块的力距和重量相乘看成一个整体,然后按从小到达排序,放都是先放轻的,这样避免倾斜,因为两个支点,所有杆子的重量可以加在两边

     3.按最小的放,如果放下去了,无论如何都会歪的话,那就结束了,表示怎样拿都会歪的

                  4.将距离乘以2,避免精度错误

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct node{
	int len;
	int weight;
};

node left[30],right[30],res[30];
int L,W,N;
int  lenl, lenr;
bool flag;
int C;

bool judge(int l, int r) {
	int suml = 0, sumr = 0;
	for(int i = 0; i < l; i++)
		suml = suml + ( -left[i].len * 2 - 3) * left[i].weight;
	for(int i = 0; i < r; i++)
		sumr = sumr + (right[i].len * 2  + 3) * right[i].weight;
	sumr += C;
	if(suml > sumr) return false;

	suml = 0; sumr = 0;

	for(int i = 0; i < l; i++)
		suml = suml + ( -left[i].len * 2 + 3) * left[i].weight;
	for(int i = 0; i < r; i++)
		sumr = sumr + (right[i].len * 2  - 3) * right[i].weight;
	suml += C;
	if(suml < sumr) return false;
	return true;
}


void dfs(int cur, int l , int r) {
	if(cur == N) {
		flag = true;
		for(int i = N - 1; i >= 0 ; i--)
			printf("%d %d\n",res[i].len,res[i].weight);
		return ;
	}

	for(int i = l ; i < lenl ; i++)
		if(judge(i,r) && !flag) {
			res[cur].len = left[i].len;
			res[cur].weight = left[i].weight;
			dfs(cur+1,i+1,r);
		}
		else
			break;
	for(int i = r; i < lenr ; i++) 
		if(judge(l,i) && !flag) {
			res[cur].len = right[i].len;
			res[cur].weight = right[i].weight;
			dfs(cur+1,l,i+1);	
		}
		else
			break;
}

int main() {
	int mark = 1;
	while(scanf("%d%d%d",&L,&W,&N) != EOF && L ) {
		lenl = lenr = 0;
		for(int i = 0; i < N; i++) {
			int t1,t2;
			scanf("%d%d",&t1,&t2);
			if(t1 < 0) {
				left[lenl].len =  t1;
				left[lenl++].weight = t2;	
			}
			else {
				right[lenr].len = t1;
				right[lenr++].weight = t2;	
			}	
		}
		node temp;
		for(int i = 0; i < lenl; i++)
			for(int j = i + 1; j < lenl; j++) 
				if((-left[i].len*2-3)*left[i].weight > (-left[j].len*2-3)*left[j].weight) {
					temp = left[i];
					left[i] = left[j];
					left[j] = temp;
				}
		for(int i = 0; i < lenr; i++)
			for(int j = i + 1; j < lenr; j++) 
				if((right[i].len*2-3)*right[i].weight > (right[j].len*2-3)*right[j].weight) {
					temp = right[i];
					right[i] = right[j];
					right[j] = temp;
				}
		C = 3 * W;		
		flag = false;	
		printf("Case %d:\n",mark++);
		dfs(0,0,0);
	
		if(!flag)
			printf("Impossible\n");	
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值