poj 2513解题报告

题目来源:http://poj.org/problem?id=2513

题目大意:

给你n根木棒,每个木棒两端都涂有颜色,任意两根木棒可以连在一起,如果他们有一端颜色是相同的,问你最后是否能把所有的木棒连成一根。

题目分析:

这道题是一个欧拉通路的判断,但是令人纠结的是,节点不是整数而是字符串,很头疼啊= =

如果不了解欧拉通路可以自己百度一下。。

因为节点是字符串,所以我们要把它转换成整数的节点,这就涉及到字符串的查找,但是map在这题是会超时的。。。所以想到可以用AC自动机

代码实现:

#include <cstdio>
#include <cstring>
using namespace std;

typedef char char_t;//字符的类型,需要的话可以改成int等
const int SIGMA=26;//字符集的大小
const int ELEMENT_MAX=5000100;//trie图中最多可能的节点数,用于内存管理
#define MAX 500010
int father[MAX],rank[MAX];
int ID;
char s1[MAX/2][15],s2[MAX/2][15];
int d[MAX];
int degree[MAX];
bool vis[MAX];
int len1[MAX/2],len2[MAX/2];
struct TrieGraph
{
    struct trie
    {
        bool match;
        int id;
        trie *pre,*child[SIGMA];
        trie():match(false),pre(0)
        {
            memset(child,0,sizeof(child));
            id = -1;
        }
        void* operator new(size_t, void *p)
        {
            return p;
        }
    } root,superroot;
    static char storage[ELEMENT_MAX*sizeof(trie)];
    static trie* data;
    static void init()
    {
        data=(trie*)storage;
    }
    void insert(char_t* s,int n) //在trie中插入一个长度为n的字符串s
    {
        //如果需要在trie节点中记录某些信息,一般是在这个函数里添加
        trie* t=&root;
        for(int i=0; i<n; ++i)
        {
            char_t c=s[i];
            if(!t->child[c])
            {
                t->child[c]=new((void*)data++) trie;
                if(i == n-1)
                {
                    ID++;
                }
            }
            t=t->child[c];
        }
        if(!t->match)
        {
            t->match=true;
            t->id = ID;
        }
    }
    void build_graph() //所有的插入完毕后,将trie树扩充为图
    {
        static trie* Q[ELEMENT_MAX];
        superroot.pre=root.pre=&superroot;
        for(int i=0; i<SIGMA; ++i)
            superroot.child[i]=&root;
        int head=0,tail=0;
        Q[tail++]=&root;
        while(head!=tail)
        {
            trie* t=Q[head++];
            t->match|=t->pre->match;
            for(int i=0; i<SIGMA; ++i)
            {
                if(t->child[i])
                {
                    t->child[i]->pre=t->pre->child[i];
                    Q[tail++]=t->child[i];
                }
                else
                    t->child[i]=t->pre->child[i];
            }
        }
    }
    int match(char_t* s,int n) //返回长度为n的字符串s中有否已被插入的字符串的匹配
    {
        trie* t=&root;
        for(int i=0; i<n; ++i)
        {
            t=t->child[s[i]];
        }
        return t->id;
    }
};
char TrieGraph::storage[ELEMENT_MAX*sizeof(trie)];
TrieGraph::trie* TrieGraph::data;
void make_set()
{
    int i;
    for(int i=1; i<=MAX/2; i++)
    {
        rank[i] = 0;
        father[i] = i;
    }
}
int find_set(int x)
{
    if(x != father[x])
    {
        father[x] = find_set(father[x]);
    }
    return father[x];
}

void union_set(int x,int y)
{
    x = find_set(x);
    y = find_set(y);
    if(rank[x] > rank[y])
        father[y] = x;
    else
    {
        father[x] = y;
        if(rank[x] == rank[y])
        {
            rank[y]++;
        }
    }
}
int main()
{
    TrieGraph::init();
    TrieGraph g;
    ID = 0;
    int k=0;
    int cnt = 0;
    memset(degree,0,sizeof(degree));
    memset(vis,0,sizeof(vis));
    make_set();
    while(scanf("%s %s",s1[k],s2[k]) != EOF)
    {
        //printf("%s %s\n",s1[k],s2[k]);
        len1[k]=strlen(s1[k]);
        for(int i=0; i<len1[k]; ++i)
            s1[k][i]-='a';
        g.insert(s1[k],len1[k]);
        len2[k]=strlen(s2[k]);
        for(int i=0; i<len2[k]; ++i)
            s2[k][i]-='a';
        g.insert(s2[k],len2[k]);
        k++;
    }
    g.build_graph();
    int ii=0;
    for(int i=0; i<k; ++i)
    {
        //printf("%d %d\n",len1[i],len2[i]);
        int d1 = g.match(s1[i],len1[i]);
        int d2 = g.match(s2[i],len2[i]);
        if(!vis[d1])
        {
            d[ii++] = d1;
            vis[d1] = true;
        }
        if(!vis[d2])
        {
            d[ii++] = d2;
            vis[d2] = true;
        }
        degree[d1]++;
        degree[d2]++;
        union_set(d1,d2);
    }
    for(int i=0; i<ii; i++)
    {
        if(degree[d[i]] % 2 == 1)
            cnt++;
    }
    memset(vis,false,sizeof(vis));
    int ans = 0;
    if(cnt==1 || cnt >= 3)
    {
        printf("Impossible\n");
    }
    else
    {
        int fanum=0;
        for(int i=0; i<ii; i++)
        {
            int fa = find_set(d[i]);
            //printf("%d %d\n",d[i],fa);
            if(!vis[fa])
            {
                vis[fa] = true;
                ans++;
            }
        }
        if(ans > 1)
            printf("Impossible\n");
        else
            printf("Possible\n");
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值