【构造,欧拉路径】cf1152E-Neko and Flashback

题意

有一个长度为n的数组k,然后有2个长度为n-1的数组b和c

b[i]=min(k[i],k[i+1]),c[i]=max(k[i],k[i+1]);

然后把b,c按照一样的方法打乱得到b1,c1

现在给你b1,c1,让你构造出一个数组,在经过上述操作后能得到b1,c1

题解

考虑题目中给的例子1

5 4 5 3 5 6 7 4 6

我们从上往下看,分为4组(4,6),(5,7),(3,4),(5,6)

(4,6)表示的意思是什么呢?在某一个位置j,min(k[j],k[j+1])=4,max(k[j],k[i+1])=6

那么在j和j+1这个位置,要么是(4,6),要么是(6,4),显然2者只能选其一

那么我们就可以把每一列转化为1条无向边,然后把所有边连起来

这个不就是欧拉路径嘛

扫描二维码关注公众号,回复: 6538119 查看本文章

但是有一点值得注意的就是这个值的范围比较大,所以我们需要把这些值紧凑一下,用一个map就好;

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5+100;
multiset<int> to[N];
int len[N];
int road[N],k;
void dfs(int x){
    for(auto a=to[x].begin();a!=to[x].end();a=to[x].begin()){//auto类型为C++11标准,可进行自动类型推断
        int u=*a;
        to[x].erase(a);
        to[u].erase(to[u].find(x));//删边
        dfs(u);//递归
    }
    road[k++]=x;//往答案队列里插入答案
}
int n;
int x[N],y[N];
bool flag;
map<int,int> m;
int p[2*N];
int cnt;
int main(){
    int a,b;
    flag=true;
    scanf("%d",&n);
    for(int i=1;i<n;i++)cin>>x[i];
    for(int i=1;i<n;i++)cin>>y[i];
    for(int i=1;i<n;i++){
        if(m.count(x[i])==0){
            p[cnt]=x[i];
            m[x[i]]=cnt++;
        }
        if(m.count(y[i])==0){
            p[cnt]=y[i];
            m[y[i]]=cnt++;
        }
        a=m[x[i]];
        b=m[y[i]];
        if(x[i]>y[i])flag=false;
        len[a]++,len[b]++;
        to[a].insert(b);
        to[b].insert(a);
    }
    int s=-1,e=-1;//起点与终点
    if(!flag){
        cout<<-1<<endl;
        return 0;
    }
    for(int i=0;i<cnt;i++)
        if(len[i]%2==1){
            if(s==-1)s=i;
            else if(e==-1)e=i;
            else {
                cout<<-1<<endl;
                return 0;
            }
        }//判断每个点的度数
    if(s==-1)s=0;
    dfs(s);//开始递归
    if(k==n)for(k=k-1;k>=0;k--)
        printf("%d ",p[road[k]]);//倒序输出答案
    else cout<<-1<<endl;
    return 0;
}
​

猜你喜欢

转载自blog.csdn.net/wang_viscaria/article/details/92656087