這個題,正賽的時候也沒有過,不過其實已經有了正確的解法,可惜時間不多了,就沒有去嘗試。
題意是有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[100005]; stack<int>stk; vector<int>v; int main() { vis[0]=1; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=1;i<=n;i++)vis[i]=0; v.clear(); while(1) { if(n<=1)break; stk.push(n); if(n%2)n=(n-1)/2-1; else n=n/2-1; } int now=1; while(1) { v.push_back(now); vis[now]=1; if(!vis[now-1])now--; else { if(stk.empty())break; else if(now*2==stk.top()) { now*=2; stk.pop(); } else if(now*2+1==stk.top()) { now=now*2+1; stk.pop(); } else { if(!vis[now*2])now=now*2; else now=now*2+1; } } } for(i=0;i<v.size();i++)printf("%d%c",v[i],i==v.size()-1?'\n':' '); } return 0; }