Codeforces 1361 C Johnny and Megans Necklace —— dfs,創造歐拉回路

This way

題意:

有n個珍珠,每個珍珠有兩個頭,每個頭都有一個值,如果兩個珍珠的兩個頭相連的話,就會得到一個值k:假設兩個值是a,b,k就是a^b之後的二進制位上一個1的位置,如果是a=b,那麼k=20
現在要將這些珍珠連成一個圓,並且你的答案是所有得到的值中最小的值,問你這個值最大是多少。

題解:

這道題對我來說是有點難了,因爲我基本上不碰圖論的題目,首先肯定是從大到小枚舉k,因爲只有20,然後將數劃分爲2k2^{k}種情況,一開始我是想要找一個哈密頓迴路,但是它的時間好像是O(n2)O(n^2)的,於是這道題目宣告破產。
然後去看cf大神們的代碼,發現是可以直接dfs,在回溯的時候將數放到答案中,這很神奇,我也想了一會才能理解。
首先要判斷每種情況的珍珠的數量是否是偶數,如果不是的話,那說明無法構成歐拉回路。否則的話可以直接dfs,因爲珍珠間連邊的話,一定是值&2k12^k-1之後是相同的才能連邊,於是就算找到一條死路也無妨,由於是回溯的時候將數放到答案中,所以可以看成是從死路來的,舉個例子,就拿第7個樣例來舉例:
5
5 1
5 0
5 10
6 6
10 2
假設現在k=1
首先進去的是,然後由於有另一端,所以到了2,2找到了3,3必須連到4,4找到了6,6必須找5,然後發現是死路,退回到6,由於6必須連5,所以退回到了4,找到了7,然後是8,然後是9,10
那麼最後答案是5,6,10,9…,2,1
就可以發現,就算走到5的時候將與他相等的數用光了也沒有關係,由於每種情況都是偶數所以前面一定有一個與他相等的,然後在回退的時候爲什麼能保證與6相連的一定是和他相等的數呢,因爲4與6相等,之後4連得邊有一定與4相等,比如這裏找到了7,那麼7與6就是可以相鄰的。
有丶東西
我用的是unordered_map,時間複雜度較差,可以考慮不用
在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int link[N];
int n;
unordered_map<int,vector<int> >Q;
int vis[N],a[N];
int cal(int x,int y){return x-((x>>y)<<y);}
vector<int>vec;
void dfs(int x,bool f,int bit){
    vis[x]=1;
    if(f)
        dfs(link[x],0,bit);
    else{
        while(1){
            int v=cal(a[x],bit);
            while(Q[v].size()&&vis[Q[v].back()])
                Q[v].pop_back();
            if(Q[v].empty())
                break;
            int ne=Q[v].back();
            Q[v].pop_back();
            dfs(ne,1,bit);
        }
    }
    vec.push_back(x);
}
int check(int bit){
    vec.clear();
    Q.clear();
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n*2;i++)
        Q[cal(a[i],bit)].push_back(i);
    for(int i=1;i<=n*2;i++)
        if(Q[cal(a[i],bit)].size()%2)
            return 0;
    dfs(1,1,bit);
    return vec.size()==n*2;
}
int main()
{

    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i*2-1],&a[i*2]);
        link[2*i-1]=2*i;
        link[2*i]=2*i-1;
    }
    int ans=20;
    while(ans){
        if(check(ans))
            break;
        ans--;
    }
    printf("%d\n",ans);
    check(ans);
    for(auto i:vec)
        printf("%d ",i);
    printf("\n");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章