zoukankan      html  css  js  c++  java
  • 洛谷P1127 【词链】欧拉通路,欧拉回路+dfs

    p1127(dfs+欧拉通路/回路)


    题目链接

    1.题目分析

    我们需要找出一条包含所有单词,这些单词在词链中出现且仅出现一次,且字典序最小的链。

    假设我们对每一个单词连一条从首字母指向尾字母的有向边,假设存在这样的一条链,那么我

    们所建成的图中便一定存在欧拉通路或者欧拉回路。

    欧拉通路 从一点出发,可以经过图中每一条边的路径,被称作欧拉通路,无向图中欧拉

    欧拉通路存在的条件:若图中有且仅由两个点的出度不等于入度,且一点的出度=入度+1,另一

    点的入度=出度+1,则图中存在欧拉通路,且起点为出度较大的点,终点为入度较大的点。

    欧拉回路:从图中任意一点出发,可经过所有边且回到起点的路径

    有向图欧拉回路判断条件:所有点的出度等于入读

    注意,欧拉回路和通路存在的必要条件是基图联通

    首先,为什么我们要建无向图而不是有向图?考虑到词链不可反转(假设词链ab.bc合法,那么c

    b.ba不合法),所以只能建有向图

    为什么一定要存在欧拉回路或者通路呢?

    分析题目,我们将单词转化为边,那么所求的词链一定是一条欧拉通路

    有了这个前提,这道题就很容易解决的,

    我们将找词链转化为有向图找欧拉通路

    但词链的起点怎么确定呢?

    假设图中存在欧拉回路,那么从任意点出发都可以,但我们要求字典序最小,所以必须从字典

    序最小的单词的首字母出发

    假设图中仅有欧拉通路,那么只有从通路起点出发才可经过所有边。

    因为我们需要求字典序最小的词链,所以选点按字典序从小开始选即可

    分析到这,代码就可以写出来了

    建图后先通过并查集来判是否连通,统计出度入度判断图的类型,找到起点按字典序来dfs即可
    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<string>
    using namespace std;
    const int maxn=1e3+10;
    int n;
    string st[maxn];
    struct node{
    	int s,t;
    }e[maxn];
    int cu[maxn];
    int ru[maxn];
    int fla[maxn];
    int cnt;
    void add(int x,int y){
    	cnt++;
    	e[cnt].s=x;
    	e[cnt].t=y;
    }
    int f[maxn];
    int find(int x){
    	if(f[x]!=x){
    		return f[x]=find(f[x]);
    	}
    	else
    		return x;
    }
    int tot;
    bool jud(){
    	for(int i=1;i<=26;i++){
    		f[i]=i;
    	}
    	for(int i=1;i<=cnt;i++){
    		int a=e[i].s;
    		int b=e[i].t;
    		int fa = find(a),fb = find(b);
            if(fa != fb) f[fa] = fb;
    	}
    	int cn=0;
    	for(int i=1;i<=26;i++){
    		if(fla[i]&&f[i]==i){
    			cn++;
    		}
    	}
    	if(cn-1!=tot){
    		return false;
    	}
    	return true;
    }
    int vis[maxn];
    int p;
    int ans[maxn];
    void dfs(int now){
    	for(int i=1;i<=n;i++){
    		if(st[i][0]-'a'+1==now&&!vis[i]){
    			vis[i]=1;
    			dfs(st[i][st[i].length()-1]-'a'+1);
    			p++;
    			ans[p]=i;
    		}
    	}
    	return ;
    }
    int main(){
    //	freopen("a.in","r",stdin);
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		cin>>st[i];
    	}
    	int a,b;
    	sort(st+1,st+1+n);//从小到大排序,目的是在dfs过程中得到最优解 
    	for(int i=1;i<=n;i++){
    		//cout<<st[i]<<endl;
    		a=st[i][0]-'a'+1;//得到字符串的起始字符 
    		b=st[i][st[i].length()-1]-'a'+1;//终止字符 
    	//	cout<<a<<" "<<b<<endl;
    		add(a,b);
    //		add(b,a) ;
    		if(!fla[a])
    			fla[a]=1;//记录该字符是否出现,目的是判断联通 
    		if(!fla[b])
    			fla[b]=1;
    		cu[a]++;//出度 
    		ru[b]++;//入度 
    	}
    //	cout<<jud();
    	if(!jud()){
    		cout<<"***";
    		return 0;
    	}
    	int s=0;
    	int t=0;
    	int to=0;
    	for(int i=1;i<=26;i++){
    		if(ru[i]!=cu[i]){
    			to++;//	
    			if(cu[i]-ru[i]==1){
    				s=i;	
    			}
    			if(ru[i]-cu[i]==1){
    				t=i;
    			}
    			}
    			else if(abs(cu[i]-ru[i])>1){
    				cout<<"***";
    				return 0;
    			}
    			if(to==2&&(!s||!t)){
    				cout<<"***";
    				return 0;
    			}
    	}
    	if(to==1||to>2){
    		cout<<"***";
    		return 0;
    	}
    	if(s!=0){
    		dfs(s);
    	}
    	else{
    		dfs(st[1][0]-'a'+1);
    	}
    	for(int i=p;i>=1;i--){
    		cout<<st[ans[i]];
    		if(i>1)
    			cout<<'.';
    	}
    	return 0;
    }
    
  • 相关阅读:
    学习日记-- 动态性。动态编译,静态方法,包装类
    第一周学习所获———ORM,数据持久化,通过注解来实现数据持久化框架
    第一周学习所获--class类1(反射和类加载过程)
    各种命名规范
    用easyui,json,纯mvc实现一个系统的数据流动过程
    js+bootstrap实现分页页码
    Echarts简单案例
    bootstrap日期控件(双日期、清空等问题解决)
    三种方法实现调用Restful接口
    Spring MVC异常处理 和 重定向传递数据
  • 原文地址:https://www.cnblogs.com/rpup/p/13783437.html
Copyright © 2011-2022 走看看