poj 庆典的日期

庆典的日期
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 2006 Accepted: 203

Description

古斯迪尔文明曾在约10亿年前在地球上辉煌一时,尤其在历法、数学、天文等方面的发展水平已经超过现代。在古城的众多庙宇中,考古人员都发现了一种奇特的建筑,该建筑包含一排独立的房间。
以下是一个规模较小的建筑的内部结构,包括9个房间:

在每个房间的中央,挂有一个转盘,每个转盘分为6个格子,每个格子写着一个1到9的数字。转盘可以逆时针转动。转盘的红色标记始终指向上方的格子。每个房间的转盘都不相同。
CC考古工作室近日成功地破译了当时的文字,对进一步研究古斯迪尔文明作出了重要贡献。首先,研究人员翻译了当时的宗教书籍,得知了建筑的用途。 原来每个寺院都要在建成以后每隔若干年举行一次大型的庆典。由于?天机不可泄漏?,寺院方面并不直接说明庆典的日期,而是采用?暗示?的方法。奇特的建筑 就是为了确定庆典的日期而专门建造的。
房间从左到右编号为1,2,3,卬,同时寺院有n个祭司也从1到n编号,这些祭司每年到房间中祈祷一次。建寺那年祭司和自己编号相同的房间祈祷。 同时,转盘上红色标记指示的格子的数字就是该祭司第二年祈祷的房间编号。在祭司祈祷完毕以后,将转盘逆时针旋转一格。转盘的设计使得在每年祈祷时,每个房 间只有一个祭司。
从建寺以后,当某一年祈祷时,每个祭司的编号都和祈祷房间的编号相同时,就是举行庆典的日期。实际上,每隔若干年,就会有一次庆典。
作为CC考古工作室的首席软件顾问,你负责编程求出第一次举行庆典的确切日期。

Input

文件第一行是两个整数n,p,n表示房间的数目(也就是祭司的数目),p表示转盘包含的格子的数目。(0 < n, p <= 200)
以下有n行,每行p个整数,表示每个房间转盘的格子上的数字。每行第一个数表示寺院建立时红色标记指向的数字,以下的数字按照顺时针方向给出。

Output

仅一行,表示第一次举行庆典是在建寺以后多少年。如果永远不会出现符合条件的情况或者第一次符合条件的年份超过10^9(那时古斯迪尔文明已经衰落了),则输出'No one knows.'

Sample Input

6 3
2 6 3
1 1 1
4 4 6
6 3 5
3 2 2
5 5 4

看的别人的代码,还是不是很理解呀,先贴这,等以后再想吧;

代码
View Code
 1 #include <iostream>
2 #include <cstdio>
3 using namespace std;
4
5 const int maxn=210;
6 int a[210][210],b[210][210];
7 int c[maxn][maxn],d1[maxn],d2[maxn];
8 int n,p;
9 int egcd(int a,int b,int& x,int& y)
10 {
11 if(b==0)
12 {
13 x=1;
14 y=0;
15 return a;
16 }
17 int t=egcd(b,a%b,y,x);
18 y-=(a/b)*x;
19 return t;
20 }
21 int solve(int w1[],int w2[],int n)
22 {
23 int x,y,d,t,ret=w1[0],temp=w2[0];
24 for (int i = 1; i <n; ++i)
25 {
26 d = egcd(temp,w2[i],x,y);
27 if ((w1[i] - ret) % d != 0)
28 {
29 return -1;
30 }
31 t = w2[i] / d;
32 x = (x * (w1[i] - ret) / d % t + t) % t;
33 ret = x * temp + ret;
34 temp = temp * w2[i] / d;
35 ret = (ret % temp + temp) % temp;
36 }
37 return ret;
38 }
39 bool find(int w1[],int w2[],int k,int &y,int &x)
40 {
41 x=1,y=-1;
42 if(k==w2[k]) y=0;
43 int t=w1[k];
44 while(t!=k)
45 {
46 if(t==w2[k]) y=x;
47 t=w1[t];
48 x++;
49 }
50 if(y==-1)
51 return 0;
52 return 1;
53 }
54 int main()
55 {
56 while(scanf("%d%d",&n,&p)!=EOF)
57 {
58 for(int i=0;i<n;i++)
59 {
60 for(int j=0;j<p;j++)
61 {
62 scanf("%d",&a[j][i]);
63 a[j][i]--;
64 }
65 }
66 for(int i=0;i<n;i++)
67 b[0][i]=a[0][i];
68 for(int i=1;i<p;i++)
69 for(int j=0;j<n;j++)
70 {
71 b[i][j]=a[i][b[i-1][j]];
72 }
73 for(int i=0;i<p;++i)
74 for(int j=0;j<n;++j)
75 c[i][b[i][j]]=j;
76 int mm=100000000;
77 for(int i=0;i<p;i++)
78 {
79 int mark=-1;
80 for(int j=0;j<n;j++)
81 {
82 mark=find(b[p-1],c[i],j,d1[j],d2[j]);
83 if(!mark) break;
84 }
85 if(!mark) continue;
86 int tt=solve(d1,d2,n);
87 if(tt!=-1&&tt*p+i+1<mm)
88 mm=tt*p+i+1;
89
90 }
91 if(mm!=100000000)
92 printf("%d\n",mm);
93 else
94 printf("No one knows.\n");
95 }
96 return 0;
97 }


转载于:https://www.cnblogs.com/one--world--one--dream/archive/2011/11/04/2236429.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值