瑞瑞的木棍(stick)
【问题描述】
瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这些木棍连在一起拼成一条线,并且使得木棍与木棍相接触的两端颜色都是相同的,给出每根木棍两端的颜色,请问是否存在满足要求的排列方式。
例如,如果只有2根木棍,第一根两端的颜色分别为red,blue,第二根两端的颜色分别为red,yellow,那么blue---red|red----yellow便是一种满足要求的排列方式。
【输入文件】
输入有若干行,每行包括两个单词,表示一根木棍两端的颜色,单词由小写字母组成,且单词长度不会超过10个字母,最多有250000根木棍。
【输出文件】
如果木棒能够按要求排列,输出Possible,否则输出Impossible
【样例输入】
bluered
redviolet
cyanblue
bluemagenta
magentacyan
【样例输出】
Possible
【解答】
待解决问题:(1)如何将字符串转化为数组下标
(2)如何判断可以连成一条直线
解决办法:(1)用hash表,花一般为特定,把字符串转化为某一特定数字。
(2)欧拉回路,1.强连通图(并查集) 2.可找到一路径串起所有点(度为奇数的点要么有两个,要么没有)
另:并查集(路径压缩) ---可用于最小生成树
find函数:找祖先,有公共祖先=>连通,每次把遍历过的所有点直接连到最上面的点 时间复杂度:O(N)
var
a,b,f,u,v:array[1..250000] of longint;
ff:boolean;
s:string;
tot,t1,id,i,j,x,y:longint;
t:int64;
function find(x:longint):longint;
var
m:longint;
begin
if f[x]=x then exit(x);
m:=find(f[x]);
f[x]:=m;
find:=m;
end;
begin
assign(input,'stick7.in');reset(input);
tot:=0;
t1:=0;
while not eof do begin
readln(s);
inc(t1);
t:=0;id:=0;
for i:=1 to length(s) do
if s[i]=' ' then break
else begin
inc(id);
t:=t+id*(id+1)*ord(s[i])*(ord(s[i])-96);
end;
t:=t mod 250001;
inc(a[t]);
u[t1]:=t;
if a[t]=1 then begin
inc(tot);
b[tot]:=t;
end;
t:=0;id:=0;
for j:=i+1 to length(s) do begin
inc(id);
t:=t+id*(id+1)*ord(s[j])*(ord(s[j])-96);
end;
t:=t mod 250001;
inc(a[t]);
v[t1]:=t;
if a[t]=1 then begin
inc(tot);
b[tot]:=t;
end;
end;
ff:=true;
t:=0;
for i:=1 to tot do
if a[b[i]] mod 2=1 then inc(t);
if not((t=0) or (t=2)) then begin
writeln('Impossible');
halt;
end;
for i:=1 to tot do f[b[i]]:=b[i];
for i:=1 to t1 do begin //并查集,求连通性
x:=find(u[i]);y:=find(v[i]);
if x<>y then f[x]:=y;
end;
t:=find(b[1]);
for i:=1 to tot do
if find(b[i])<>t then begin
ff:=false;
break;
end;
if ff then writeln('Possible')
else writeln('Impossible');
readln;
end.