POJ 2513 Colored Sticks

题目链接:

题目大意:

  • 有一些木棍,木棍两端有不同的颜色;
  • 两个木棍能够排列到一块,当且仅当两个木棍相邻端点颜色一样;
  • 问这些木棍能否全部链接到一块;

解题思路:

  • 首先,可以将每一个颜色,看做是一个点;
  • 木棍就可以看做为两个颜色之间的一条边;
  • 然后就可以组成一个图;
  • 问这个图是否是一个欧拉图;
  • 对于每一个颜色,可以用map映射成一个数字。但是由于数据过大,用map会超时,所以改为用一个字典树来映射。在C++11中可以用unordered_map来映射,复杂度按理说是可以。然后用并查集判断所有点是否在一个图中,然后记录端点的入度和出度就可以判断出结果

字典树版本

#include<iostream>
#include<string.h>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;

const int N = 500007;

vector<int>many(N, 0), Rank(N, 0), par(N);

void init()
{
    for(int i=0; i<N; ++ i)
        par[i] = i;
}

int Find(int x)
{
    if(x == par[x])
        return x;
    else
        return par[x] = Find(par[x]);
}

void unite(int x, int y)
{
    x = Find(x);
    y = Find(y);
    if(x == y)
        return ;

    if(Rank[x] < Rank[y])
        par[x] = y;
    else
    {
        par[y] = x;
        if(Rank[x] == Rank[y])
            Rank[x] ++;
    }
}

struct node
{
    int x;
    node *next[26];
    node()
    {
        x = -1;
        for(int i=0; i<26; ++ i)
            next[i] = NULL;
    }
};

node *root = new node();


void Insert(string &str, int n)
{
    node *head = root;
    size_t i = 0;
    while( i < str.size())
    {
        if(head->next[str[i] - 'a'] == NULL)
            head->next[str[i] - 'a'] = new node();
        head = head->next[str[i] - 'a'];
        i ++;
    }
    head->x = n;
}

int Search(string &str)
{
    node *head = root;
    size_t i = 0;
    while(i < str.size())
    {
        if(head->next[str[i] - 'a'] == NULL)
            return 0;
        head = head->next[str[i] - 'a'];
        i ++;
    }
    if(head->x == -1)
        return 0;
    return head->x;
}

int main()
{
    ios::sync_with_stdio(false);

    init();
    string a, b;
    int n = 0;
    int x = 0, y = 0;

    while(cin >> a >> b)
    {
        x = Search(a);
        if(x == 0)
            Insert(a, x = ++ n);
        y = Search(b);
        if(y == 0)
            Insert(b, y = ++ n);
        many[x] ++, many[y] ++;
        unite(x, y);
    }

    x = 0, y = 0;
    for(int i=1; i<=n; ++ i)
    {
        if(par[i] == i)
            x ++;
        if(many[i]&1)
            y ++;
    }
    if(x > 1 || y == 1 || y > 2)
        cout << "Impossible" << endl;
    else
        cout << "Possible" << endl;
    return 0;
}

unordered_map版本

#include<iostream>
#include<string.h>
#include<vector>
#include<unordered_map>
#include<string>
#include<algorithm>
using namespace std;

const int N = 500007;

int par[N], Rank[N];


unordered_map<string, int>mp;
vector<int>many(N, 0);

void init()
{
    for(int i=0; i<N; ++ i)
        par[i] = i, Rank[i] = 0;
}

int Find(int x)
{
    if(x == par[x])
        return x;
    else
        return par[x] = Find(par[x]);
}

void unite(int x, int y)
{
    x = Find(x);
    y = Find(y);
    if(x == y)
        return ;

    if(Rank[x] < Rank[y])
        par[x] = y;
    else
    {
        par[y] = x;
        if(Rank[x] == Rank[y])
            Rank[x] ++;
    }
}


int main()
{
    ios::sync_with_stdio(false);

    init();
    string a, b;
    int n = 0;
    while(cin >> a >> b)
    {
        if(mp[a] == 0)
            mp[a] = ++ n;
        if(mp[b] == 0)
            mp[b] = ++ n;
        many[mp[a]] ++, many[mp[b]] ++;
        unite(mp[a], mp[b]);
    }
    int x = 0, y = 0;
    for(int i=1; i<=n; ++ i)
    {
        if(par[i] == i)
            x ++;
        if(many[i]&1)
            y ++;
    }
    if(x != 1 || y & 1 || y > 2)
        cout << "Impossible" << endl;
    else
        cout << "Possible" << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/aiterator/p/6565692.html