刷题记录-luoguP1341 无序字母对

这是一道欧拉路径的问题

欧拉路径:对于无向图,当且仅当奇数度为0或2时,存在欧拉路径,即可以不重复的经过每一条边。

(1)当奇数度为0时,即所有节点的边数都是偶数时,肯定能回来(n条边,n/2条出来,n/2条回来),故叫做欧拉回路

(2)当奇数度为2时,这两个相应的奇数度节点一定一个是起点,一个是终点,否则做不到不重复的经过每一条边。

*************************************

对于这题,可以把字母对拆开,

对于样例:

4
aZ
tZ
Xt
aX
可拆成:a Z t X

然后连无向边,比如aZ就把a和Z连起来

计算节点的度数,相应的按照欧拉路径来处理,

对于(1),可按照优先级搜索,保存边的vector可以排序,很方便

对于(2),设两点为v u,如果v<u直接以v为起点搜下,否则以u为起点搜下

注意:记录使用的b数组(或者说“used”数组),是记录边的使用,不是节点的使用情况

如果记录节点,那么可能是aZ Zt ta,这样会炸的。

***************************************

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#define MAXN 3005
#define MAXM 65
using namespace std;
int n;
vector<int> G[MAXM];
int b[MAXM][MAXM];
int ans[MAXN];
int temp[MAXM];
int cnt;
int dfs(int x,int k){
    if(k>n-cnt){
        return 1;
    }
    for(int i=0;i<G[x].size();i++){
        int y=G[x][i];
        if(!b[x][y]){
            b[x][y]=b[y][x]=1;
            if(dfs(y,k+1)){
                ans[k]=y;
                return 1;
            }
            b[x][y]=b[y][x]=0;
        }
    }
}
int read(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        char x,y;
        cin>>x>>y;
        x-='A'; y-='A';
        if(x==y){
            G[x].push_back(y);
        }
        else{
            G[x].push_back(y);
            G[y].push_back(x);
            temp[x]++;
            temp[y]++;
        }
    }    
    for(int i=0;i<MAXM;i++){
        sort(G[i].begin(),G[i].end());
    }
    int cnt=0;
    for(int i=0;i<MAXM;i++){
        if((temp[i]&1)){
            cnt++;
        }
    }
//    for(int i=0;i<MAXM;i++){
//        if(G[i].size()){
//            for(int j=0;j<G[i].size();j++)
//                printf("(%c,%c)\n",i+'A',G[i][j]+'A');
//        }
//    }
    if(cnt&&cnt!=2){
        printf("No Solution\n");
        return 1;
    }
    if(cnt){
        int u=0,v=0;
        for(int i=0;i<MAXM;i++){
            if((temp[i]&1)){
                if(u){
                    v=i;
                    break;
                }
                else{
                    u=i;
                }
            }
        }
        if(u<v){
            ans[0]=u;
            dfs(u,1);
        }    
        else{
            ans[0]=v;
            dfs(v,1);
        }    
        for(int i=0;i<=n;i++){
            printf("%c",ans[i]+'A');
        }
        return 1;
    }
    return 0;
}
int main()
{
//    freopen("data.in","r",stdin);
//    freopen("my.out","w",stdout);
    if(read())
        return 0;
    cnt=1;
    for(int i=0;i<MAXM;i++){
        if(temp[i]){
            ans[0]=i;
            ans[n]=i;
            if(dfs(i,1)){
                for(int i=0;i<=n;i++){
                    printf("%c",ans[i]+'A');
                }
                return 0;
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值