POJ 2513 trie+并查集+欧拉路

题目大意:每根木棒两端有颜色,能否拼成一条线,当然连接木棒的两端颜色要相同。

思路:欧拉路:(1)、该图是连通的(2)、节点度数为偶数,或者奇数度节点数不超过2。并查集可以很好求得连通性,至于节点就是每一种颜色,要用到并查集就要用到数字编号,所以就要把每一种颜色的的编号表示出来,所以用到trie。

 

program:

#include<iostream>
#define maxn 500005
int num,r[maxn],total[maxn];
struct point
{
 int n;
 point *next[26];
}*head;
void inti(point * &p)  //这个指针引用实在不是很懂,(要么传递指向指针的指针进来, 要么使用指针的引用)不过当模板使用先,创建链表的时候
{
 p=new point;
 p->n=-1;
 memset(p->next,0,sizeof(p->next));
}
int change(char * in)
{
 //int a;
 point *p;
 p=head;
 int len=strlen(in);
 for(int i=0;i<len;i++)//修改成功!yes!
 {
   int tmp=in[i]-'a';
   if(p->next[tmp]==NULL)
      inti(p->next[tmp]);//用这个指针创建a的节点  和  创建a 的节点再用指针指着a是一样道理的
   p=p->next[tmp];      
 }
 /*while(*in++)
 {
  a=*in-'a';
  if(p->next[a]==NULL)  //这个用法有点问题,提交时候RE了,改成上面那个就AC了。
   inti(p->next[a]);
  p=p->next[a];
 }*/
 if(p->n==-1)  //如果该颜色还未使用过,则新编号,之所以用指针P来表示,是因为尽管是最后一个字母的地址,但是在串中还是唯一的地址
  p->n=num++;
 return p->n;
}
/*int findroot(int a)
{
 while(r[a]!=a)
  a=r[a];
 return a;
}*/


int findroot(int x)
{
  if(r[x]!=x)
    r[x]=findroot(r[x]);          
  return r[x];
}

bool judge1()
{
 int e=findroot(0);
 for(int i=1;i<num;i++)
  if(findroot(i)!=e)
   return false;
 return true;
}
bool judge2()
{
 int num1=0;
 for(int i=0;i<num;i++)
 {
  if(total[i]%2)
   num1++;
  if(num1>2)
   return false;
 }
 return true;
}
int main()
{
// freopen("cc.txt","r",stdin);
 char in1[11],in2[11];
 for(int i=0;i<maxn;i++)//初始化父亲
  r[i]=i;
 inti(head);
 while(scanf("%s%s",in1,in2)!=EOF)
 {
  int u,v;
  u=change(in1);//返回的是颜色编号
  v=change(in2);
  total[u]++;
  total[v]++;
  r[findroot(v)]=findroot(u);//把u的祖先当成v的祖先的祖先,包含并查集合并的一部分,只是少了高度和数目而已
 }
 if((!judge1())||(!judge2()))
  printf("Impossible\n");
 else
  printf("Possible\n");
 system("pause");
  return 0;
}

总结:先看一遍一位大牛这个博客对做这道题应该会有很不错的 帮助,尽管她写的有点繁琐:

            http://blog.csdn.net/lyy289065406/article/details/6647445

 

你可能感兴趣的:(struct,null,System)