首页 > 其他分享 >洛谷题单指南-图的基本应用-P1127 词链

洛谷题单指南-图的基本应用-P1127 词链

时间:2024-03-30 14:44:45浏览次数:27  
标签:string int 洛谷题 字母 单词 words 词链 P1127

原题链接:https://www.luogu.com.cn/problem/P1127

题意解读:按字典序排列单词,使得相邻单词的首位字母一样。

解题思路:

由于单词之间可以相邻的条件是前一个单词的末尾字母和后一个单词的开头字母一样,因此可以遍历每一个单词,再找到每一个可以接在其后面的单词,

建立一个邻接表,然后从每一个单词开始,进行DFS,如果能找到n个单词,说明词链构建成功,输出结果即可;由于需要按字典序排列,在建立邻接表前,先把单词排序即可。

80分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1005;

string words[N];
vector<int> g[N];
int n;
bool flag[N];

bool dfs(int u, int cnt, string res)
{
    if(cnt == n) //如果已经加了n个单词,输出结果
    {
        cout << res;
        return true;
    }
    for(auto v : g[u]) //找能连在单词u后面的其他单词v,依次枚举、回溯
    {
        if(!flag[v])
        {
            flag[v] = true;
            bool ret = dfs(v, cnt + 1, res + "." + words[v]);
            if(ret) return true; //如果成功,提前结束递归,否则继续回溯
            flag[v] = false;
        }
    }
    return false;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> words[i];
    sort(words + 1, words + n + 1); //按字典序排序
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(i != j && words[i][words[i].length() - 1] == words[j][0])
            {
                g[i].push_back(j); //单词i和单词j建立关联
            }
        }
    }
    bool success = false;
    for(int i = 1; i <= n; i++) 
    {
        memset(flag, 0, sizeof(flag));
        flag[i] = true;
        success = dfs(i, 1, words[i]); //从每一个单词开始进行DFS,看是否能找到一条n个单词的词链
        if(success) break;
    }
    if(!success) cout << "***";

    return 0;
}

以上方法的主要问题在于,需要从每一个单词开始进行DFS,会导致部分超时。

分析题意,对于一个词链,除了第一个单词的开头字母以及最后一个单词的结尾字母,其余单词的在开头、结尾字母应该是偶数个;

如果算上第一个单词的开头字母,如果和最后一个单词结尾字母不相等,这个字母出现在单词开头的个数一定比出现在单词结尾的次数多1,

如果找到1个这样的单词,就取该单词作为起点即可找到词链;

如果第一个单词的开头字母和最后一个单词的结尾字母相等,那么将可以形成一个环,从任意一个单词开始都可以构成词链,取字母序最小的即可;

100分代码:

 

#include <bits/stdc++.h>
using namespace std;

const int N = 1005;

string words[N];
vector<int> g[N];
int n;
bool flag[N];
char front[30], tail[30]; //字母在单词头尾出现的次数

bool dfs(int u, int cnt, string res)
{
    if(cnt == n) //如果已经加了n个单词,输出结果
    {
        cout << res;
        return true;
    }
    for(auto v : g[u]) //找能连在单词u后面的其他单词v,依次枚举、回溯
    {
        if(!flag[v])
        {
            flag[v] = true;
            bool ret = dfs(v, cnt + 1, res + "." + words[v]);
            if(ret) return true; //如果成功,提前结束递归,否则继续回溯
            flag[v] = false;
        }
    }
    return false;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> words[i];
        front[words[i][0] - 'a']++; //头字母出现次数+1
        tail[words[i][words[i].length() - 1] - 'a']++; //尾最出现次数+1
    } 
    sort(words + 1, words + n + 1); //按字典序排序
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(i != j && words[i][words[i].length() - 1] == words[j][0])
            {
                g[i].push_back(j); //单词i和单词j建立关联
            }
        }
    }

    bool success = false;
    for(int i = 1; i <= n; i++) 
    {
        if(front[words[i][0] - 'a'] - tail[words[i][0] - 'a'] == 1)
        {
            memset(flag, 0, sizeof(flag));
            flag[i] = true;
            success = dfs(i, 1, words[i]); //从首字母在开头出现次数比结尾出现次数多1的单词开始进行DFS,看是否能找到一条n个单词的词链
            if(success) break;
        } 
    }
    //从第一个单词开始dfs,处理形成环的情况
    if(!success)
    {
        memset(flag, 0, sizeof(flag));
        flag[1] = true;
        success = dfs(1, 1, words[1]);
    }
    
    if(!success) cout << "***";

    return 0;
}

 

标签:string,int,洛谷题,字母,单词,words,词链,P1127
From: https://www.cnblogs.com/jcwy/p/18105468

相关文章

  • 洛谷题单指南-图的基本应用-P1807 最长路
    原题链接:https://www.luogu.com.cn/problem/P1807题意解读:由于对于每一条边u->v,都有u<v,因此节点1的入度一定是0,且是有向无环图,直观上可以通过拓扑排序法搜索每一个节点,计算1到每一个节点的最长距离。但问题在于,入度为0的节点可能不止一个,这样在计算到某个点的最长距离时,会受到......
  • 洛谷题单指南-图的基本应用-P4017 最大食物链计数
    原题链接:https://www.luogu.com.cn/problem/P4017题意解读:食物链的顶端不会被其他生物吃,在图结构中设定为入度是0,食物链的底端不会吃其他生物,在图结构式设定为出度是0,此题就是要计算所有入度是0的点到所有出度是0的点一共有多条路径。解题思路:首先,来模拟一样样例,样例数据形成的......
  • 洛谷题单指南-图的基本应用-P3916 图的遍历
    原题链接:https://www.luogu.com.cn/problem/P3916题意解读:寻找每个点所能到达的最大的点。解题思路:直观上,可以依次从每个点开始DFS搜索,记录经过的最大点,复杂度是O(n^2)级别,会超时。可以换一种角度,既然要找每个点可以达到的最大值,那么可以反向建图,从最大值出发,所经过的点能达到......
  • 洛谷题单指南-图的基本应用-P5318 【深基18.例3】查找文献
    原题链接:https://www.luogu.com.cn/problem/P5318题意解读:图的建立、DFS、BFS模版题。解题思路:本题主要考察建图、图的DFS、BFS遍历。建图方式:领接表vector<int>g[N];需要注意的是,在DFS、BFS搜索领接点时,需要先将领接点编号排序,满足题目要求的“如果有很多篇文章可以参阅,请......
  • 洛谷题单指南-集合-P2814 家谱
    原题链接:https://www.luogu.com.cn/problem/P2814题意解读:已知多组父子关系,找某个人最早的祖先,并查集的应用。解题思路:由于存在真正的父子关系,所以在并查集合并的时候,要把p[x]=y中x设置为子,y设置为父,其余都是并查集的常规操作。由于是计算姓名之间的父子关系,并查集可以用map......
  • 洛谷题单指南-集合-P3879 [TJOI2010] 阅读理解
    原题链接:https://www.luogu.com.cn/problem/P3879题意解读:此题本质上是计算倒排索引,所谓倒排索引,即不是通过文章来找单词,而是通过单词来找文章。解题思路:要建立单词和文章之间的关系,一个单词对应多篇文章,且要按照文章编号排序,可以使用如下数据结构:map<string,set<int>>h;只......
  • 洛谷题单指南-集合-P1955 [NOI2015] 程序自动分析
    原题链接:https://www.luogu.com.cn/problem/P1955题意解读:要判断约数条件是否可以同时满足,主要是要判断不相等的情况。解题思路:对于相等的条件,直接进行集合合并即可;对于不相等的条件,判断两者是否属于同一个集合,如果形成矛盾,则条件不能成立。由于i,j的范围至10^9,定义并查集如果......
  • 洛谷题单指南-集合-P1892 [BOI2003] 团伙
    原题链接:https://www.luogu.com.cn/problem/P1892题意解读:此题与关押罪犯问题非常像,本质上就是要合并所有的朋友。解题思路:首先,初始化并查集;对于每一对人的关系,如果是朋友,直接进行合并;如果是敌人,先查看双方之前是否有记录其他敌人,如果有,则将一方与另一方的敌人进行合并,如果没......
  • 洛谷题单指南-集合-P1621 集合
    原题链接:https://www.luogu.com.cn/problem/P1621题意解读:a~b之间的数,把有大于等于p的公共质因数的数进行合并作为一个集合,求一共有多少个集合。解题思路:要进行集合合并、统计集合数,可以使用并查集,有两种做法:1、暴力法80%的数据在1000范围内,因此通过双重循环枚举,判断两个数的......
  • 洛谷题单算法1-6二分查找与二分答案
    代码仅供参考,不足之处望理解。P2249【深基13.例1】查找#include<iostream>usingnamespacestd;constintN=1e6+5;intn,m,a[N];intmain(){ios::sync_with_stdio(false);//输入cin>>n>>m;for(inti=1;i<=n;i++)cin>>a[i];for(inti=1......