ZOJ 4103 浙江省第16屆大學生程序設計競賽 D題 Traveler 構造


這個題,正賽的時候也沒有過,不過其實已經有了正確的解法,可惜時間不多了,就沒有去嘗試。

題意是有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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM