UVa-679(Dropping Balls)

对这道题。。。只能说,数学太重要了

第一次作死使用链表二叉树模拟,结果TLE

二叉树模拟(错误一):默默吐槽。。好长,流泪不止


#include<iostream>
#include<string>
#include<queue>
#include<math.h>
using namespace std;
struct Node {		//Node节点
	int data;
	bool is_on;
	Node* leftchild, *rightchild;
	Node(int Data, bool Is_on,Node* Lchild=nullptr,Node* Rchild=nullptr):data(Data),is_on(Is_on),
		leftchild(Lchild), rightchild(Rchild) {
		;
	}
};
Node* root;	//指向根节点
void create_tree(int d)		//根据深度建树
{
	bool h;
	h = false;
	root = new Node(1,h);
	queue<Node*> my_queue;
	my_queue.push(root);
	int i = 1;
	int hh = 1 << d-1;
	while (i<=hh*2)		//为每个节点编上对应的编号
	{
		Node* tmp = my_queue.front();
		my_queue.pop();
		tmp->leftchild = new Node(++i, h);
		tmp->rightchild = new Node(++i, h);
		my_queue.push(tmp->leftchild);
		my_queue.push(tmp->rightchild);
	}
}

int last_ball(int num)	//得到最后一个的位置
{
	int position = 1;
	for (int i = 0; i < num; i++)
	{
		Node* tmp = root;
		while (tmp->rightchild != nullptr)
		{
			if (tmp->is_on == false)
			{
				tmp->is_on = true;
				tmp = tmp->leftchild;
			}
			else
			{
				tmp->is_on = false;
				tmp = tmp->rightchild;
			}
		}
		position = tmp->data;
	}
	return position;
}

void deleteTreeHelp(Node* r)
{
	if (r != nullptr)
	{
		if (r->leftchild != nullptr)
			deleteTreeHelp(r->leftchild);
		if (r->rightchild != nullptr)
			deleteTreeHelp(r->rightchild);
		delete r;
	}
}

void deleteTree()		//每次循环后需要删除树
{
	deleteTreeHelp(root);
}


int main(void)
{
	int d, num;		//d为深度,	//num为小球个数
	int position;	//最终的位置
	while (cin >> d >> num && d != -1)
	{
		create_tree(d);	//先根据深度建树
		position = last_ball(num);	//模拟num个小球下落过程
		cout << position << endl;	
		deleteTree();	//删除树
	}
}

然后只能去看紫书,第一种TLE的方法,也是模拟,但因为用的是数组(完全二叉树用数组很方便,为什么之前没想到),代码就不放出来了,最后还是TLE,因为还是很耗时。

只能拿出最终武器,利用数学方法(之前做约瑟夫环的时候也是这样,数学方法特别重要),思路是这样的:

1.因为每个节点的状态要么是开启,要么是关闭,所以可以用取模运算进行判断

2.其中比较精华的是,用I=(I+1)/2 OR I /= 2 来判断小球是第几个落在该节点,这一点非常棒,而且只需要对最后一个小球进行模拟

代码如下:

#include<cstring>
#include<cstdio>
const int maxd = 20;
int s[1 << maxd];
int main(void)
{
	int D, I;
	int count;
	scanf("%d", &count);
	while (scanf("%d%d", &D, &I) == 2)
	{
		int k = 1;
		for (int i = 0; i < D - 1; i++)
		{
			if (I % 2) {
				k = k * 2; I = (I + 1) / 2;		//奇偶性。。
			}
			else {
				k = k * 2 + 1;	I /= 2;
			}
		}
		printf("%d\n", k);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值