2012福建省信息学奥林匹克CCF NOIP夏令营第三天训练




瑞瑞的木棍(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.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值