[2020多校联考]组合

2020.11.21

解法

把每种字符看成一个点,把每个简单词看成一条边((T=1) 时是无向边,(T=2) 时是有向边)。那么问题就转换为寻找一条路径,使得该路径不重复地走过所有边,即寻找欧拉路径。

一张无向图包含欧拉路径,当且仅当所有点的度数为偶或者恰好有两个度数为奇的节点。一张无向图包含欧拉回路,当且仅当所有点度数为偶。一张有向图包含欧拉路径,当且仅当所有点的入度和出度相等或者恰好有一个节点的出度等于入度加一且又一个节点的入度等于出度加一。一张有向图包含欧拉回路,当且仅当所有点的入度和出度相等。

按以上判定,若有欧拉路,直接dfs,在遍历某条边结束的时候将该边加入栈,最后弹栈输出栈内元素。加上当前弧优化,复杂度 (O(N+M))

#include<stdio.h>
#include<string.h>
#define N 100007
#define M 200007
 
inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}
 
struct E{
    int next,to,p;
    bool vis;
}e[M<<1];
int T,n,m,in[N],out[N],d[N];
int head[N],cnt=0;
 
inline void add(int id,int to,int p){
    e[++cnt]=(E){head[id],to,p,0};
    head[id]=cnt;
}
 
inline int min(int x,int y){return x<y? x:y;}
int ans[M],top=0,p[M];
void dfs1(int u){
    for(int i=head[u];~i;i=min(head[u],e[i].next)){
        if(e[i].vis) continue;
        e[i].vis=e[i^1].vis=1;
        head[u]=e[i].next;
        dfs1(e[i].to);
        ans[++top]=e[i].p;
    }
}
 
void dfs2(int u){
    for(int i=head[u];i;i=min(head[u],e[i].next)){
        if(e[i].vis) continue;
        e[i].vis=1;
        head[u]=e[i].next;
        dfs2(e[i].to);
        ans[++top]=e[i].p;
    }
}
 
void print(){
    printf("YES
");
    for(int i=top;i;i--)
        if(ans[i]) printf("%d ",ans[i]);
}
 
int main(){
    T=read(),m=read(),n=read();
    if(!n) printf("YES
");
    else if(T==1){
        cnt=-1;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++){
            int u=read(),v=read();
            add(u,v,i),add(v,u,-i);
            d[u]++,d[v]++;
        }
        while(head[p[1]]==-1) p[1]++;
        int tag=0;
        for(int i=1;i<=m;i++)
            if(d[i]&1) p[++tag]=i;
        if(!tag||tag==2){
        //  if(tag) add(p[2],p[1],0),add(p[1],p[2],0);
            dfs1(p[1]);
            if(top==n) print();
            else printf("NO
");
        }else printf("NO
");
    }else{
        for(int i=1;i<=n;i++){
            int u=read(),v=read();
            add(u,v,i);
            in[v]++,out[u]++;
        }
        while(!head[p[1]]) p[1]++;
        bool tag1=0,tag2=0,tag3=0;
        for(int i=1;i<=m;i++){
            if(in[i]==out[i]) continue;
            if(!tag1&&in[i]==out[i]+1) tag1=1,p[2]=i;
            else if(!tag2&&in[i]==out[i]-1) tag2=1,p[1]=i;
            else tag3=1;
        }
        if(tag3||(tag1^tag2)) printf("NO
");
        else{
        //  if(tag) add()
            dfs2(p[1]);
            if(top==n) print();
            else printf("NO
");
        }
    }
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/14024151.html