大致题意:
给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。
解题思路:
可以用图论中欧拉路的知识来解这道题,首先可以把木棒两端看成节点,把木棒看成边,这样相同的颜色就是同一个节点
问题便转化为:
给定一个图,是否存在“一笔画”经过涂中每一点,以及经过每一边一次。
这样就是求图中是否存在欧拉路Euler-Path。
回顾经典的“七桥问题”,相信很多同学马上就明白了什么是 欧拉路 了,这里不多作解释。
由图论知识可以知道,无向图存在欧拉路的充要条件为:
① 图是连通的;
② 所有节点的度为偶数,或者有且只有两个度为奇数的节点。
这题目大致一看,觉得应该可以用Map做,简单方便,不过,数据太大,肯定会超时。
知识点考察的也是是否存在欧拉回路问题。
1.度数好说,用一个一维数组就能记录了,然后分别 模2,就能判断颜色结点的奇偶性
只要奇度数的结点数的个数 = 1 或 >=3 ,即使①图连通,欧拉路也必不存在。
2.图的连通性用并查集,最后如果只有一棵树,肯定是联通的。
问题在于度数的记录,string类用Map太慢,考虑用字典树生成ID,不知道这题用hash可不可以,待会试试。
第二段代码是用hash做的,不知道为什么RuntimeError了
#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#include <stdio.h>
using namespace std;
const int large=500000;
int color=0;
int degree[large+11]={0};
int ancestor[large+11];
class TireTreeNode
{
public:
int id;
bool flag;
TireTreeNode* next[27];
TireTreeNode()
{
id=0;
flag=false;
memset(next,0,sizeof(next));
}
}root;
int find(int x)
{
if(ancestor[x]!=x)
ancestor[x]=find(ancestor[x]); //路径压缩
return ancestor[x];
}
void union_set(int a,int b)
{
int pa=find(a);
int pb=find(b);
ancestor[pb]=pa; //使a的祖先 作为 b的祖先
return;
}
int hash(char* s)
{
TireTreeNode* p=&root;
int len=0;
while(s[len]!='\0')
{
int index=s[len]-'a'+1;
if(!p->next[index])
{
p->next[index]=new TireTreeNode;
}
p=p->next[index];
len++;
}
if(p->flag)
return p->id;
else
{
p->flag=true;
p->id=++color;
return p->id;
}
}
int main()
{
for(int k=0;k<large+11;k++)
ancestor[k]=k;
char a[111],b[111];
while(cin>>a>>b)
{
int x1=hash(a);
int x2=hash(b);
degree[x1]++;
degree[x2]++;
union_set(x1,x2);
}
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;
}
#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#include <stdio.h>
using namespace std;
const int large=500000;
int color=0;
int degree[large+11]={0};
int booldegree[large+11]={false};
int ancestor[large+11];
int compute_k(char s[111])
{
__int64 key=0;
for(int i=0;i<strlen(s);i++)
{
key+=s[i]*s[i]*(i+1);
}
key%=large;
int intkey=key;
return intkey;
}
int find(int x)
{
if(ancestor[x]!=x)
ancestor[x]=find(ancestor[x]); //路径压缩
return ancestor[x];
}
void union_set(int a,int b)
{
int pa=find(a);
int pb=find(b);
ancestor[pb]=pa; //使a的祖先 作为 b的祖先
return;
}
int main()
{
for(int k=0;k<large+11;k++)
ancestor[k]=k;
char a[111],b[111];
int test;
bool btest=true;
while(cin>>a>>b)
{
int x1=compute_k(a);
int x2=compute_k(b);
degree[x1]++;
booldegree[x1]=true;
degree[x2]++;
booldegree[x2]=true;
if(btest)
{
test=x1;
btest=false;
}
union_set(x1,x2);
}
int s=find(test);
int num=0;
for(int i=0;i<large+1;i++)
{
if(booldegree[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;
}