荒岛野人

本文介绍了一种模拟多个野人在有限数量的山洞中按规律迁徙而不相遇的算法。通过数学方法解决野人在给定寿命内不发生碰撞所需的最少山洞数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。

奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?

Input

输入文件的第1行为一个整数N(1<=N<=15),即野人的数目。第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=10^6 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。

Output

输出文件仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。

分析

对于一个合法的m,必须满足的是n个人两两之间必须不能走重合。现在的问题是如何判定了。对于每两个人我们都可以算出他们走到同一个点的最短时间。
列出式子就是:ci+pi*x=cj+pj*x(mod m),再转化:(pi-pj)*x-my=cj-ci
那么我们已知pi-pj,m,cj-ci现在要求的是x。
这样就有了ax+by=c。这样一个式子已经很接近同余方程了,但不是。
同余方程是ax+by=gcd(a,b)。对此若上面的方程有解那么必有c%gcd(a,b)=0
这样可以转化成a’x+b’y=c’而a’=a/gcd(a,b),b’,c’类似。
此时再转化:a’x’+b’y’=1.那么求出x’后x=x’*c/gcd(a,b)。然而这里求出的x,y只是一组可行解,并不是最小解。
这里有:
a(x-b)+b(y+a)=gcd(a,b)
a(x-2b)+b(y+2a)=gcd(a,b)
。。。。。
a(x+2b)+b(y-2a)=gcd(a,b)
……..
所以我们只需把x%b’,就可以得到x>0且x最接近0的解了。(注意这里是b’)

找出了x的时候,再判断一下x是否<=min(l[i],l[j]),若是的话m便不合法,否则反之。

最后注明一下这里的每个式子转化时除的数必须是可以整除,所以我们才类似的用a/gcd(a,b)

var
    n,i,k,j,ma,a,b,d,x,y,cc:longint;
    c,p,l:array[1..15] of longint;
    bz:boolean;
function max(l,r:longint):longint;
begin
    if l<r then exit(r) else exit(l);
end;
function exgcd(a,b:longint;var x,y:longint):longint;
var t,er:longint;
begin
    if b=0 then begin
       x:=1;y:=0;exit(a);
    end else begin
       er:=exgcd(b,a mod b,x,y);
       t:=x;
       x:=y;
       y:=t-(a div b)*y;
       exit(er);
    end;
end;
function min(l,r:longint):longint;
begin
    if l<r then exit(l) else exit(r);
end;
begin
    readln(n);
    for i:=1 to n do begin
        readln(c[i],p[i],l[i]);
        ma:=max(ma,c[i]);
    end;
    for k:=ma to 1000000 do begin
        bz:=true;
        for i:=1 to n-1 do begin
           for j:=i+1 to n do begin
               a:=p[i]-p[j];b:=k;cc:=c[j]-c[i];
               if (k=6)and(i=2) then
                 n:=n;
               d:=exgcd(a,b,x,y);
               if cc mod d<>0 then continue;
               x:=(x*cc div d) mod (b div d);
               if x<0 then x:=x+abs(b div d);
               if x<=min(l[i],l[j]) then begin
                  bz:=false;break;
               end;
           end;
        if not bz then break;
        end;
        if bz then break;
    end;
    writeln(k);
close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值