老办法,先吃辣条!! 哎呀!这就是模拟啊== (不许要模拟~)(不~~)(你用吧~~)
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(<100),第2行给出K个互不相同的待验证的正整数n(1<n<=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无所谓吗?)(嗯?我说了吗~~)