这个题,正赛的时候也没有过,不过其实已经有了正确的解法,可惜时间不多了,就没有去尝试。
题意是有n个点,i点能通向i-1,然后i和i*2、i*2+1互通。
请你构造一种路径从1能走完所有点,并且不重复经过每个点。
一开始我先考虑了有什么方法能固定地走完所有点。
然后发现 1-(2)-(4)-3-(6)-5-(10)....()为跳跃
仅当走完了之前的所有点时才跳跃,跳跃完后再回退走完所有点。
这样走的话,是可以走完所有点的。
但是这样的限制是,我们只能在n=1/2/4/6/10...这些数时走完所有点,这个可行的集合可以用ai=(a(i-2)+1)*2来递推。
换句话说,我们只要求出数列a 就可以按这个数列走出方案。
这个题目i可以通向i*2,也可以通向i*2+1,所以我们得到了另一种移动方式ai=(a(i-2)+1)*2+1。
这样我们能走的数就多了许多(其实是全部数都能走完 233)
我们只要从ai=n 反向推这个数列前面的项,显然a(i-2)=ai/2-1或者(ai-1)/2-1
而且这个其实是固定的,奇数的话想/2一定要-1,偶数反之。
然后我们就求出了这个数列的ap ap-2 ap-4.....
数列的其他项其实不重要 只要满足ap>ap-1即可,可以随便构造(大概)。
以下为具体代码
#include<bits/stdc++.h>
using namespace std;
int i,i0,n,m,T;
bool vis[];
stack<int>stk;
vector<int>v;
int main()
{
vis[]=;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=;i<=n;i++)vis[i]=;
v.clear();
while()
{
if(n<=)break;
stk.push(n);
if(n%)n=(n-)/-;
else n=n/-;
}
int now=;
while()
{
v.push_back(now);
vis[now]=;
if(!vis[now-])now--;
else
{
if(stk.empty())break;
else if(now*==stk.top())
{
now*=;
stk.pop();
}
else if(now*+==stk.top())
{
now=now*+;
stk.pop();
}
else
{
if(!vis[now*])now=now*;
else now=now*+;
} }
}
for(i=;i<v.size();i++)printf("%d%c",v[i],i==v.size()-?'\n':' ');
}
return ;
}