题目大意:
有n(250000)根木棍,每根的两端都有颜色,问你这些木棍能不能连成一条直线,各个接口的两根木棍的颜色都相每根棍子两端的颜色都是通过一个长度不超过10个字符的字符串来给出的。
他并没有问你怎么连而是让你判断能不能连起来.如果把各个端点如果颜色相同就看成一个点(即使木棍的两端都是相同颜色),那么,该问题可转化成一笔画问题(欧拉回路)。如果该图存在欧拉回路并且连通,那么就满足题目要求。
用并查集检测该图是否连通(不过要记得优化,层数不能太高),存500000个数,想通过stl的map把颜色string映射成int,但是超时了,据说好像是因为map太慢了。。。。
改成用字典树,要是要把所有的可能的结点都建出来,26的10次方肯定是存不开的,所有就要用一个节点就开一个节点。
虽然超时了,但是还是附上用map写的代码吧:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<map>
#define N 5000500
using namespace std;
int n=1;
int d[N]={0};
int boss[N]={0};
map<string,int>mp;//把字符串映射成数
void ceshi1()
{
for(int i=1;i<n;i++)
{
cout<<d[i]<<" ";
}
}
void init()//建立并查集
{
for(int i=1;i<N;i++)
{
boss[i]=i;
}
}
void connect(int x,int y)//并查集xy连接
{
if(boss[x]==x&&boss[y]==y)
{
if(x>y)boss[x]=y;
else boss[y]=x;
return;
}
boss[x]=boss[boss[x]];
boss[y]=boss[boss[y]];
connect(boss[x],boss[y]);
}
int main()
{
string l1,l2;
char ls1[10]={0};
char ls2[10]={0};
init();
int t=sizeof(ls1);
while(scanf("%s%s",ls1,ls2)!=EOF)
{
//if(ls1[0]=='0')break;
l1=ls1;l2=ls2;
int a,b;
if(mp.count(l1)==0)
{
mp[l1]=n;
a=n;
n++;
}
else a=mp[l1];
d[a]++;
if(mp.count(l2)==0)
{
mp[l2]=n;
b=n;
n++;
}
else b=mp[l2];
d[b]++;
connect(a,b);
memset(ls1,0,t);
memset(ls2,0,t);
}
int count=0;
for(int i=1;i<n;i++)
{
if(d[i]&1==1)count++;
if(count>2)
{
cout<<"Impossible";
return 0;
}
}
for(int i=2;i<n;i++)
{
if(boss[i]==i)
{
cout<<"Impossible";
return 0;
}
}
cout<<"Possible";
//ceshi1();cout<<count;
}
用trie树的ac代码:
#include<iostream>
#include<string.h>
#include<stdio.h>
#define N 5000500
using namespace std;
struct trie
{
int id;//以该点为结尾的字符串的编号
trie *next[27];
bool flag;//该点是否已经用到过
int v;//该点代表的字符
trie()
{
flag=0;
for(int i=0;i<27;i++)
{
next[i]=NULL;
}
id=0;
}
};
trie root;
int num[N]={0};//每个字符串出现的次数
int n=1;//记录字符串的总个数
int boss[N]={0};
int find(int x)
{
while(boss[x]!=x)
{
boss[x]=boss[boss[x]];
x=boss[x];
}
return x;
}
void connect(int x,int y)
{
if(boss[x]==x&&boss[y]==y)
{
boss[x]=y;
return;
}
connect(find(x),find(y));
}
void init()
{
for(int i=0;i<N;i++)
{
boss[i]=i;
}
}
int add(char *x)
{
trie *p=&root;
for(int i=0;i<strlen(x);i++)
{
int t=(int)x[i]-'a'+1;
if((*p).next[t]==NULL)
{
(*p).next[t]=new trie;
p=(*p).next[t];
*p=*p;
(*p).v=t;
}
else
{
p=(*p).next[t];
}
}
if((*p).id==0)
{
(*p).id=n;
n++;
return n-1;
}
else return (*p).id;
}
int main()
{
char a[10]={0};
char b[10]={0};
init();
while(scanf("%s%s",a,b)!=EOF)
{
int x=add(a);
int y=add(b);
//cout<<x<<" "<<y<<endl;
num[x]++;
num[y]++;
connect(x,y);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
}
int count=0;
for(int i=1;i<n;i++)
{
if(num[i]%2==1)count++;
if(count>2)
{
cout<<"Impossible";
return 0;
}
}
count=0;
for(int i=1;i<n;i++)
{
if(boss[i]==i)count++;
if(count>1)
{
cout<<"Impossible";
return 0;
}
}
cout<<"Possible";
}
这道题主要的关键应该就是如何用字典树(trie树)来使得字符串映射成整数;