1005 继续(3n+1)猜想 (25)(25 分)

老办法,先吃辣条!! 哎呀!这就是模拟啊== (不许要模拟~)(不~~)(你用吧~~)
1005 继续(3n+1)猜想 (25)(25 分)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对n=3进行验证的时候,我们需要计算3、5、8、4、2、1,则当我们对n=5、8、4、2进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这4个数已经在验证3的时候遇到过了,我们称5、8、4、2是被3“覆盖”的数。我们称一个数列中的某个数n为“关键数”,如果n不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式:每个测试输入包含1个测试用例,第1行给出一个正整数K(&lt100),第2行给出K个互不相同的待验证的正整数n(1&ltn<=100)的值,数字间用空格隔开。

输出格式:每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用1个空格隔开,但一行中最后一个数字后没有空格。

输入样例:

6
3 5 6 7 8 11

输出样例:

7 6

第一感觉 超级无敌大模拟 

好吧!这个办法失败了! 看我的错误思路

错误思路: 用一种东西保存住 每一个值 和它所覆盖的数字 然后 来循环 判断两个值能不能覆盖 如果两个完全覆盖那么这两个数就是结果。

都说当局者迷。嗯 写出来的思路满满的逻辑错误,那多个呢?多个刚好覆盖全部数 我只观察两个情况肯定是不行的。所以错误。

错误代码NOT AC:

#include <bits/stdc++.h>


using namespace std;


map<int, int>TS;
pair<vector<int>, int>DD[1000]; // 剩余量 对应值
typedef pair<vector<int>, int> pv;
int kn;	int inp;
void init() {
	for (map<int, int>::iterator it = TS.begin(); it != TS.end(); it++)
		(*it).second = 1;
}


int panduan(pv A,pv B) { // 只是观察两个情况 所以不正确  

	set<int>ENT;
	ENT.insert(A.first.begin(), A.first.end()); // 但是学会了 这样 insert 好开心 
	ENT.insert(B.first.begin(), B.first.end());
	ENT.insert(A.second);
	ENT.insert(B.second);
	return ENT.size() >= inp ? 1 : 0;
}


vector<int> dg(int x) { // 应该加上 容器 找到就 -- 


	if (x == 1) {
		return DD[kn].first;
	}
	if (x % 2 != 0) {
		if (TS.find((3 * x + 1) / 2) != TS.end()) {
			TS[(3 * x + 1) / 2] = 0;
			DD[kn].first.push_back((3 * x + 1) / 2);
		}
		dg((3 * x + 1) / 2);
	}
	else if (x % 2 == 0) {
		if (TS.find(x / 2) != TS.end()) {
			TS[x / 2] = 0;
			DD[kn].first.push_back(x / 2);
		}
		dg(x / 2);
	}
	return DD[kn].first;
}


void solve() {


	queue<int>ST;


	cin >> inp;
	for (int i = 0, ts; i<inp; i++) {


		cin >> ts;
		ST.push(ts);
		TS[ts] = 1;
	}
	pair<vector<int>, int>DD[1000]; // 剩余量 对应值  原理 是 用find 找 
	
	for (int i = 0; !ST.empty(); ST.pop()) {
		kn = i;
		DD[i].first = dg(ST.front());
		DD[i].second = ST.front();
		i++;
		init();
	}
	set<pv>DEEP_ASE;
	for (int i = 0; i < inp; i++) {
		for (int j = i+1; j < inp; j++) {
			if (panduan(DD[i], DD[j])) {   //       错误所在行,注意看这个函数
				DEEP_ASE.insert(DD[i]);
				DEEP_ASE.insert(DD[j]);
			}
		}
	}
	for (set<pv>::iterator it = DEEP_ASE.end(); it != DEEP_ASE.begin(); it--)
		if (it != DEEP_ASE.end()) cout << (*it).second << " ";
	if (DEEP_ASE.size())
		cout << (*DEEP_ASE.begin()).second << endl;
	




}


int main() {


	solve();
	return 0;
}

正视错误!而不是重新写代码!!马上调整为 覆盖论 

思路: 填数,怎么个填法呢? 我在查询的递归之中 填满足以下条件的数进 集合 set<> (也可以使用 C 语言的数组存,这里主要用C++)

1.不是查询本身的数

2.是输入数据之间的数

为什么选择set<>?因为集合之中的元素保证是唯一存在的(我写到这里觉得用容器也可以 哈哈~~) 看的比较舒服吧,主要是有find函数可以用。嗯心里话。我是个直男!

然后使用 find 来找出 满足以下条件的数字 进入 容器 vector<>(同理,c语言可以使用数组+二分搜索代替)

然后sort一下(用优先队列转栈输出可以,使用集合存储find的值然后倒着输出也可以,因为我想要vector<>所以就sort)

sort:递增排序,但是我不写 cmp 函数 都知道我很懒的 用尽一切力量来搞掉一些函数 其实··我写的已经够复杂了,但是能对我感觉好欣慰。/爱心 ❥ 爱你哦  

然后超级无敌伪大模拟出炉 也就是第一个AC代码出解(我严重怀疑是因为测试数据不好导致AC的)

#include <bits/stdc++.h>

using namespace std;

map<int, int>TS;
pair<vector<int>, int>DD[1000]; // 剩余量 对应值
typedef pair<vector<int>, int> pv;
int kn;	int inp;
void init() {

	for (map<int, int>::iterator it = TS.begin(); it != TS.end(); it++)
		(*it).second = 1;
}

vector<int> dg(int x) { // 应该加上 容器 找到就 -- 

	if (x == 1) {
		return DD[kn].first;
	}
	if (x % 2 != 0) {
		if (TS.find((3 * x + 1) / 2) != TS.end()) {
			TS[(3 * x + 1) / 2] = 0;
			DD[kn].first.push_back((3 * x + 1) / 2);
		}
		dg((3 * x + 1) / 2);
	}
	else if (x % 2 == 0) {
		if (TS.find(x / 2) != TS.end()) {
			TS[x / 2] = 0;
			DD[kn].first.push_back(x / 2);
		}
		dg(x / 2);
	}
	return DD[kn].first;
}

void solve() {

	queue<int>ST;

	cin >> inp;
	for (int i = 0, ts; i<inp; i++) {

		cin >> ts;
		ST.push(ts);
		TS[ts] = 1;
	}
	pair<vector<int>, int>DD[1000]; // 剩余量 对应值  原理 是 用find 找 
	
	for (int i = 0; !ST.empty(); ST.pop()) {
		kn = i;
		DD[i].first = dg(ST.front());
		DD[i].second = ST.front();
		i++;
		init();
	}
	set<int>DEEP_ASE;
	vector<int>SNTE;
	for (int i = 0; i < inp; i++) {
		DEEP_ASE.insert(DD[i].first.begin(), DD[i].first.end());
	}
	for(int i=0;i<inp;i++)
		if (DEEP_ASE.find(DD[i].second) == DEEP_ASE.end()) {
			SNTE.push_back(DD[i].second);
		}
	sort(SNTE.begin(), SNTE.end());
	for (vector<int>::iterator it = SNTE.end(); it != SNTE.begin(); it--) // 绕开 cmp
		if (it != SNTE.end()) printf("%d ",*it);
	if (!SNTE.empty()) // 这样也很好的避开了末尾空格问题 嗯!!(*^▽^*)
		cout << *SNTE.begin();



}

int main() {

	solve();
	return 0;
}

AC了之后,作为绕了远路的我怎么能够放弃重写代码的机会!既然是填数问题 条件与上例相同(省字ing~) 然后 

AC代码 2.0

#include <bits/stdc++.h>

using namespace std;


// 覆盖

set<int>S1;
vector<int>CC;

void Callatz_3n_1(int x) {

	if (x == 1) return;
	if (x % 2 != 0) {
		if (find(CC.begin(), CC.end(), (3 * x + 1) / 2)!=CC.end()) // 永远只存下一元素
			S1.insert((3 * x + 1) / 2);
		Callatz_3n_1((3 * x + 1) / 2);
	}
	else if (x % 2 == 0) {
		if (find(CC.begin(),CC.end(),x/2)!=CC.end())
			S1.insert(x / 2);
		Callatz_3n_1(x / 2);
	}
}


void solve() {

	int x;
	cin >> x;
	vector<int>AC;
	for (int i = x,t; i--;) {
		cin >> t;
		CC.push_back(t);
	}
	for (int i = 0; i < x; i++)
		Callatz_3n_1(CC[i]); // 填数
	for (int i = 0; i < x; i++)
		if (S1.find(CC[i]) == S1.end()) //查找  ==end() 就是没找到 我要的就是没找到的
			AC.push_back(CC[i]); // 存起来
	sort(AC.begin(),AC.end());// sort一下
	for (vector<int>::iterator it = AC.end(); it != AC.begin(); it--) // 绕开 cmp
		if(it!=AC.end()) printf("%d ", *it);
	if (!AC.empty())// 判断非空 只要非空 肯定存在首部
		cout << AC[0];
}

int main() {

	solve();
	system("pause");
	return 0;
}
编程我觉得应该这样学才快乐 !!如果只是为了写出AC代码,而遗漏了很多好玩的小知识点,我觉得这个损失我承受不了。A不AC无所谓,哈哈~~ 爱你这道题让我AC~~!(你不是说A不AC无所谓吗?)(嗯?我说了吗~~)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值