POJ2513-Colored Sticks(并查集 欧拉回路)

来源:互联网 发布:知返景行全文阅读19楼 编辑:程序博客网 时间:2024/05/22 06:59

标题目大意

给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。

分析

我们以一个节点表示一种颜色,将每个木棍两端的颜色连上边。这样原问题变成了求一个图是或否存在欧拉图的问题了(tip:欧拉图的典型例子是哥尼斯堡七桥问题,哈密尔顿图的典型问题是旅行商问题)

总结

欧拉图:

欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路。

欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路。

无向图是否具有欧拉通路或回路的判定:

欧拉通路:图连通;图中只有0个或2个度为奇数的节点

欧拉回路:图连通;图中所有节点度均为偶数

有向图是否具有欧拉通路或回路的判定:

欧拉通路:图连通;除2个端点外其余节点入度=出度;1个端点入度比出度大1;一个端点入度比出度小1 或 所有节点入度等于出度

欧拉回路:图连通;所有节点入度等于出度

哈密顿图:

在图为无向连通图的前提下,经过每个顶点一次且仅一次,若最终回到出发点则称为哈密顿图,哈密顿图为NP完全问题,暂不存在多项式时间内的解法,数据少的题可以用动态规划来做,复杂度是log2nn2

代码

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>using namespace std;const int INF=999999999;int pa[500005];int degree[500005];int number=0;struct Node{      Node *next[30];//0~25      int id;      bool End;};Node *root;void Init_Trie(){    root=new Node;    for(int i=0;i<=25;i++)root->next[i]=NULL;    root->End=0;    root->id=0;}int Insert(char *s){    int n=strlen(s);    Node * p=root;    for(int i=0;i<n;i++)    {          if(p->next[s[i]-'a']==NULL)          {                Node *temp=new Node;                temp->End=0;                for(int j=0;j<=25;j++)                      temp->next[j]=NULL;                p->next[s[i]-'a']=temp;          }            p=p->next[s[i]-'a'];    }    if(p->End==1)    {          return p->id;    }    else    {          p->End=1;          p->id=++number;          return p->id;    }}int Find(int x){      return pa[x]!=x? pa[x]=Find(pa[x]) : x;}void Union(int a,int b){      int x1=Find(a);      int x2=Find(b);      if(x1!=x2)      {            pa[x1]=x2;      }      return ;}int main(){     char a[20],b[20];     Init_Trie();     int T=0;     for(int i=1;i<=500000;i++)pa[i]=i;     while(scanf("%s %s",a,b)!=EOF)     {          int t1=Insert(a);          int t2=Insert(b);          //cout<<t1<<" "<<t2<<endl;          degree[t1]++;          degree[t2]++;          Union(t1,t2);          T++;          //if(T==5)break;     }     int flag=0;     int x=Find(1);     for(int i=2;i<=number;i++)     {           if(Find(i)!=x){flag=1;break;}     }     int t=0;     for(int i=1;i<=number;i++)     {           if(degree[i]%2!=0)t++;     }     if(t!=2 && t!=0)flag=1;     if(flag==1)cout<<"Impossible"<<endl;     else cout<<"Possible"<<endl;}
0 0
原创粉丝点击