POJ 2513 字典树

3 篇文章 0 订阅
1 篇文章 0 订阅

POJ 2513 字典树

题意:

题目给你了一些木棒,这些木棒前后有颜色,现在问你可不可能将这些接起来按照木棒的颜色来连接。题目的木棒数量是25w。

思路:

我们将这些木棒的端点看成图里面的端点,木棒本身作为图的边,那么这时候这道题就转化成求这些木棒(边)组成的图里面是否有存在欧拉图。
欧拉图:通过图中的所有边并且只通过一次的通路为欧拉图,图为有向图或无向图。
那么无向图是欧拉图的充要条件是:
  • 图是连通的
  • 图中存在欧拉通路当且仅当图中的节点仅有零个或两个度为奇数的节点。
此时问题就经过转化了。然后我们明确两个任务:
  • 判断是否存在多个连通分量
  • 存在多少个度数为奇数的节点
现在来解决第一个问题:判断是否存在多个连通分量
如果把这些点先看成n颗树,那么如果能够连接起来就代表这些点属于一个根,也就是连上其他的树。那么如何表示这个关系呢—-并查集。我们可以利用并查集来先让这些节点作为单独的树,然后若是一根木棒,那么就把这两个节点连接在一起。
第二个问题:存在多少个度数为奇数的节点
怎样让这些节点标号呢,如果我们用map容器,那么根据前人的经验,这个是不行的,看来POJ专门卡STL。于是我们首先要将这些节点进行标号,此时采用Trie,能根据前缀快速的定位这个单词是否出现过。这就是为什么这道题需要采用字典树的原因,并且这个字典树需要动态进行建树。将节点标号后需要就在对应的degree数组里面进行++。
#include<iostream>
#include<string>
using namespace std;
#define maxn 500100
int tree[maxn];
int color;
int degree[maxn];//度数
typedef struct node
{
    bool flag;
    struct node *next[27];
    int id;
    node()
    {
        id = 0;
        flag = false;
        memset(next,0, sizeof(next));//将这个节点下一层的所有节点变成NULL,保证
                                     //这时候没有新的节点。
    }
}Trie;
int find(int x)
{
    if (tree[x] != x)
        tree[x] = find(tree[x]);
    return tree[x];
}
void merge(int a, int b)
{
    int fx = find(a), fy = find(b);
    if (fx != fy)
        tree[fx] = fy;
}
int insert(Trie *root,string word)//利用字典树来进行hash
{
    Trie *p = root;
    int i = 0;
    while (word[i] != '\0')
    {
        int index = word[i] - 'a';
        if (!p->next[index])
            p->next[index] = new Trie;
        p = p->next[index];
        i++;
    }
    if (p->flag)
        return p->id;
    else
    {
        p->flag = true;
        p->id = ++color;
        return p->id;
    }
}
void init()
{
    for (int i = 0; i < maxn; i++)
        tree[i] = i;
}
int main()
{
    init();
    string a, b;
    Trie *root = new Trie;
    while (cin >> a >> b)
    {
        int i = insert(root,a);
        int j = insert(root,b);
        degree[i]++;
        degree[j]++;
        merge(i, j);
    }
    int s = find(1);
    int num = 0;//度为奇数的节点个数
    for (int i = 1; i <= color; i++)
    {
        if (degree[i] % 2 == 1)
            num++;
        if (num > 2)
        {
            cout << "Impossible" << endl;
            return 0;
        }
        if (find(i) != s)
        {
            cout << "Impossible" << endl;
            return 0;
        }
    }
    if (num == 1)
        cout << "Impossible" << endl;
    else
        cout << "Possible" << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值