【NOI2008】 假面舞会

题目描述
假面舞会
【问题描述】
一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。
今年的面具都是主办方特别定制的。
每个参加舞会的人都可以在入场时选择
一个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具
的人。
为了使舞会更有神秘感,
主办方把面具分为 k (k≥3)类,
并使用特殊的技术将
每个面具的编号标在了面具上,只有戴第 i 类面具的人才能看到戴第 i+1 类面具
的人的编号,戴第 k 类面具的人能看到戴第 1 类面具的人的编号。
参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己
算出有多少类面具,于是他开始在人群中收集信息。
栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第 2
号面具的人看到了第 5 号面具的编号。栋栋自己也会看到一些编号,他也会根据
自己的面具编号把信息补充进去。
由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信息
不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多
少类面具。由于主办方已经声明了 k≥3,所以你必须将这条信息也考虑进去。
【输入格式】
输入文件 party.in 第一行包含两个整数 n, m,用一个空格分隔,n 表示主办
方总共准备了多少个面具,m 表示栋栋收集了多少条信息。
接下来 m 行,每行为两个用空格分开的整数 a, b,表示戴第 a 号面具的人看
到了第 b 号面具的编号。相同的数对 a, b 在输入文件中可能出现多次。
【输出格式】
输出文件 party.out 包含两个数,第一个数为最大可能的面具类数,第二个数
为最小可能的面具类数。如果无法将所有的面具分为至少 3 类,使得这些信息都
满足,则认为栋栋收集的信息有错误,输出两个-1。
【输入样例一】
65
12
23
34
41
35
【输出样例一】
44
【输入样例二】
33
12
21
23
【输出样例二】
-1 -1
【数据规模和约定】
50%的数据,满足 n ≤ 300, m ≤ 1000;
100%的数据,满足 n ≤ 100000, m ≤ 1000000

 

题解

 

假面舞会
  1 (*
  2     *Problem:    假面舞会
  3     *Author :    Chen Yang
  4     *Time   :    2012.5.18
  5     *State  :    Solved
  6     *Memo    :    图论、有向图找环
  7 *)
  8 program party;
  9 const maxn=101000;
 10 type
 11   ty1=^ty2;
 12   ty2=record
 13     x,d:longint;
 14     get:boolean;
 15     next,up:ty1;
 16   end;
 17 
 18 var
 19   n,m,i,a,b,min,max,cnt,tot:longint;
 20   first:array[0..maxn] of ty1;
 21   get:array[0..maxn] of boolean;
 22   link,c,bel,cmin,cmax:array[0..maxn] of longint;
 23 //==================
 24 procedure insert(x,y,z:longint);
 25 var
 26   p,q:ty1;
 27 begin
 28   new(p);
 29   p^.x:=y; p^.d:=z; p^.get:=false;
 30   p^.next:=first[x]; first[x]:=p;
 31   new(q);
 32   q^.x:=x; q^.d:=-z; q^.get:=false;
 33   q^.next:=first[y]; first[y]:=q;
 34   q^.up:=p; p^.up:=q;
 35 end;
 36 //==================
 37 procedure find(x,i:longint);
 38 var
 39   p:ty1;
 40 begin
 41   get[x]:=true; link[x]:=i;
 42   bel[x]:=tot;
 43   p:=first[x];
 44   while p<>nil do
 45   begin
 46     if not p^.get then
 47     begin
 48       p^.get:=true; p^.up^.get:=true;
 49       if not get[p^.x] then find(p^.x,i+p^.d) else
 50       if link[p^.x]-i-p^.d<>0 then
 51       begin
 52         inc(cnt); c[cnt]:=abs(link[p^.x]-i-p^.d);
 53       end;
 54     end;
 55     p:=p^.next;
 56   end;
 57 end;
 58 //==================
 59 function gcd(x,y:longint):longint;
 60 begin if y=0 then exit(x) else exit(gcd(y,x mod y)); end;
 61 //==================
 62 procedure main1;
 63 var
 64   i:longint;
 65 begin
 66   max:=c[1];
 67   for i:=2 to cnt do max:=gcd(max,c[i]);
 68   for min:=3 to max do
 69   begin
 70     for i:=1 to cnt+1 do
 71     if c[i] mod min<>0 then break;
 72     if i=cnt+1 then break;
 73   end;
 74   if max<3 then
 75   begin
 76     min:=-1; max:=-1;
 77   end;
 78 end;
 79 //==================
 80 procedure main2;
 81 var
 82   i:longint;
 83 begin
 84   fillchar(cmin,sizeof(cmin),$7);
 85   fillchar(cmax,sizeof(cmax),200);
 86   for i:=1 to n do
 87   begin
 88     if cmin[bel[i]]>link[i] then cmin[bel[i]]:=link[i];
 89     if cmax[bel[i]]<link[i] then cmax[bel[i]]:=link[i];
 90   end;
 91   for i:=1 to tot do inc(max,cmax[i]-cmin[i]+1);
 92   if max>2 then min:=3 else
 93   begin
 94     min:=-1; max:=-1;
 95   end;
 96 end;
 97 //==================
 98 begin
 99   assign(input,'party.in'); reset(input);
100   assign(output,'party.out'); rewrite(output);
101   read(n,m);
102   for i:=1 to m do
103   begin
104     read(a,b); insert(a,b,1);
105   end;
106   for i:=1 to n do
107   if not get[i] then
108   begin inc(tot); find(i,1); end;
109   if cnt>0 then main1 else main2;
110   writeln(max,' ',min);
111   close(input); close(output);
112 end.
posted @ 2012-05-22 11:39  datam  阅读(429)  评论(0编辑  收藏  举报