Catenyms(欧拉通路)

题目:http://poj.org/problem?id=2337

分析:根据题目的意思可以想到两个方向:①把字符串当做点,两点能形成接龙形式则连一条有向边,这是问题变成求一条点不重复的路且经过每一个点。这就像一个路径覆盖问题,但是图上各种多重边让笔者不知道怎么搞所以放弃这个想法;②把字符串当做边,以26个字母为顶点建图,问题变成求边不重复的路且经过每一条边,显然这是求欧拉通路。

PS:码代码是为了求快搞了各种贪心的搞法,然后各种RE。。。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct edge
{
    int v,used;
    string s;
    bool operator<(const edge &x)const
    {
        return s<x.s;
    }
    edge(int _v,int _u,string _s):v(_v),used(_u),s(_s){};
};
vector<edge> vec[30],e;
struct node
{
    int in,out;
}nd[30];
int pre[30],vis[30];
int cnt,n,tt;
void dfs(int u)//判连通
{
    vis[u]=1;tt++;
    for(int i=0;i<vec[u].size();i++)
    {
        int v=vec[u][i].v;
        if(!vis[v])dfs(v);
    }
}
bool path(int u,int dep)//求欧拉通路
{
	if(dep==n)return true;
	for(int i=0;i<vec[u].size();i++)
	{
		if(vec[u][i].used)continue;
		vec[u][i].used=1;
		if(path(vec[u][i].v,dep+1))
		{
		    e.push_back(edge(vec[u][i].v,0,vec[u][i].s));
		    return true;
		}
		vec[u][i].used=0;
	}
	return false;
}
int main()
{
    int t;
    scanf("%d",&t);getchar();
    while(t--)
    {
        scanf("%d",&n);getchar();
        memset(nd,0,sizeof(nd));
        for(int i=0;i<26;i++)vec[i].clear();
        for(int i=0;i<n;i++)
        {
            char s[25];
            scanf("%s",s);
            int u=s[0]-'a';
            int v=s[strlen(s)-1]-'a';
            nd[u].out++;nd[v].in++;
            vec[u].push_back(edge(v,0,s));
        }
        int tot=0,flag=0;
        for(int i=0;i<26;i++)if(nd[i].out+nd[i].in>0)tot++;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<26;i++)
        {
            tt=0;
            if(nd[i].out)
            {
                memset(vis,0,sizeof(vis));
                dfs(i);
            }
            if(tt==tot){flag=1;break;}
        }
        if(!flag){printf("***\n");continue;}
        int num=0;flag=1;
        for(int i=0;i<26;i++)
        {
            if(nd[i].in!=nd[i].out)
            {
                if(abs(nd[i].in-nd[i].out)==1)num++;
                else flag=0;
            }
        }
        if((num!=0&&num!=2)||flag==0){printf("***\n");continue;}
        for(int i=0;i<26;i++)if(vis[i])sort(vec[i].begin(),vec[i].end());
        e.clear();
        if(num==0)
        {
            for(int i=0;i<26;i++)if(vis[i]){path(i,0);break;}
        }
        else
        {
            for(int i=0;i<26;i++)
            {
                if(nd[i].out>nd[i].in){path(i,0);break;}
            }
        }
        for(int i=e.size()-1;i>=0;i--)
        {
            if(i)cout<<e[i].s<<'.';
            else cout<<e[i].s<<endl;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值