求大神指教,化简程序,在500MS内输出即可

liu_Hxing 2015-10-29 05:30:22
加精
题目如下:
韩信点兵
时间限制:500MS 内存限制:65536K
题型: 编程题 语言: G++;GCC
Description 相传汉高祖刘邦问大将军韩信统御兵士多少,韩信答说,每3人一列余1人、5人一列余2人、7人一列余4人、13人一列余6人、17人一列余2人、19人一列余10人、23人一列余1人、29人一列余11人。

刘邦茫然而不知其数。你呢? 你是一位优秀的程序员,请你帮刘邦解决这一问题。


输入格式
要求由键盘输入A,B,C,D,E,F,G,H,a,b,c,d,e,f,g,h十六个数,分别代表每A人一列余a、每B人一列余b、每C人一列余c、每D人一列余D、每E人一列余e、每F人一列余f、每G人一列余g、每H人一列余h,其中A,B,C,D,E,F,G,H为互不相等的质数


输出格式
输出总兵士数,要求输出满足条件的最小的一个,但要满足8种排法的每一种排法至少可排一列。(保证给的数据,有结果且计算的结果不会超过2的63次方)


输入样例
2 3 5 7 11 13 17 19
1 1 1 1 1 1 1 1


输出样例
9699691



我的程序书写:(望大神改进,我是大一新生)
#include<stdio.h>
int main()
{
int a[8],b[8],i,t,j,n,m,s,mn,ab,k; //n最终为8个数共同的余数,m最终为8个数的最小公倍数
scanf("%d",&a[0]);
t=a[0];
for(i=1;i<8;i++)
{
scanf("%d",&a[i]);
if(t<a[i]) t=a[i];
}
for(i=0;i<8;i++) scanf("%d",&b[i]);
n=b[0]; m=a[0];
for(i=1;i<8;i++)
for(j=0;;j++)
{
mn=n+m*j;
for(k=mn/(a[i]-1),s=0,ab=0;ab<=mn;k++)
{
ab=b[i]+a[i]*k;
if(ab==mn)
{ n=ab; s=1;
m=a[i]*m;
}
if(s==1) break;
}
if(s==1)break;
}
for(i=0;;i++)
{
j=n+m*i;
if(j>t) break;
}
printf("%d",j);
return 0;
}

...全文
1796 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
y1_newbie 2016-01-22
  • 打赏
  • 举报
回复
学习学习,受教了!
cipoye15 2015-11-07
  • 打赏
  • 举报
回复
qq_31887631 2015-11-06
  • 打赏
  • 举报
回复
进来学习
qq_31970923 2015-11-04
  • 打赏
  • 举报
回复
五人一列余2,个位怎么可以是1
Homber爱分享 2015-11-02
  • 打赏
  • 举报
回复
使用网易邮箱的撤销功能,对方是看不到的被撤销的邮件的,不过只能够撤销1小时之内的哦
mkfiah512 2015-11-02
  • 打赏
  • 举报
回复
学习一下 HEHE
lwouyang 2015-11-02
  • 打赏
  • 举报
回复
5楼的思路表达得相当清晰。正确性的证明,额。。。其实这个问题就是中国余数定理啦。 我的建议也是在按照5楼的迭代思路迭代基础上有几个改进。 1,先理解迭代思路:对于A和B互素(A和B不必都是素数),余数分别是a和b,分别搜索合适的非负整数m和n, 使Am mod B = 1,Bn mod A = 1(这里m和n是必然存在的,不证明了),则 r = (Amb + Bna) mod AB为所求,将A和B合并成AB,余数对应变成了r进入下一次迭代。 2,从具体问题上考虑,应当首先获取全部输入后对余数相同的素数分别直接合并成最小公倍数(因为两两互素,所以就是乘积啦),理论上有利于减少迭代次数。 3,从前面第1点可以看到搜索m和n是最影响性能的步骤。那么问题来了,怎样更快搜索到m和n?这是我的那20%部分啦。 由1知m和n只与A和B有关,与余数无关,且由同余法则可得,小于B的m必存在,小于n的A必存在,因此 Am + Bn <AB + BA = 2AB;另一方面,事实上,令a=b=1,则r=1,即(Am + Bn) mod AB = 1。因此 满足Am + Bn = AB + 1的m和n必然存在。m和n只需要搜索其中一个另一个可直接计算不必再次搜索。 设A>B,则m的最差搜索次数小于n的最差搜索次数。 所以,为了搜索m或n的次数最优化,对素数进行大小排序可能是有必要的。迭代应当从最大的开始,理由。。你懂的。
lwouyang 2015-11-02
  • 打赏
  • 举报
回复
5楼的思路表达得相当清晰。正确性的证明,额。。。其实这个问题就是中国余数定理啦。 我的建议也是在按照5楼的迭代思路迭代基础上有几个改进。 1,先理解迭代思路:对于A和B互素(A和B不必都是素数),余数分别是a和b,分别搜索合适的非负整数m和n, 使Am mod B = 1,Bn mod A = 1(这里m和n是必然存在的,不证明了),则 r = (Amb + Bna) mod AB为所求,将A和B合并成AB,余数对应变成了r进入下一次迭代。 2,从具体问题上考虑,应当首先获取全部输入后对余数相同的素数分别直接合并成最小公倍数(因为两两互素,所以就是乘积啦),理论上有利于减少迭代次数。 3,从前面第1点可以看到搜索m和n是最影响性能的步骤。那么问题来了,怎样更快搜索到m和n?这是我的那20%部分啦。 由1知m和n只与A和B有关,与余数无关,且由同余法则可得,小于B的m必存在,小于n的A必存在,因此 Am + Bn <AB + BA = 2AB;另一方面,事实上,令a=b=1,则r=1,即(Am + Bn) mod AB = 1。因此 满足Am + Bn = AB + 1的m和n必然存在。m和n只需要搜索其中一个另一个可直接计算不必再次搜索。 设A>B,则m的最差搜索次数小于n的最差搜索次数。 所以,为了搜索m或n的次数最优化,对素数进行大小排序可能是有必要的。迭代应当从最大的开始,理由。。你懂的。
fbs09 2015-11-01
  • 打赏
  • 举报
回复
n := (d4*i + c4) mod a5; if n = b5 then begin
rosschn 2015-11-01
  • 打赏
  • 举报
回复
另补充下,这类问题,在阶数不是比较高的情况下,弄明白整数规划后,用手工都能算出来的,先去看看《运筹学》中的整数规划吧
rosschn 2015-11-01
  • 打赏
  • 举报
回复
1. 这是运筹学中典型的整数规划问题(参见清华大学出版社的《运筹学》); 2. 这类问题,不建议直接用计算机程序直接求解; 3. 建议利用运筹学中的整数规划对算法进行优化后,再用计算机程序实现,这样计算量会小很多很多; 4. 如果可能的话,再在第3步实现的基础上,增加并发计算的可能性,以提高性能。
mewiteor 2015-11-01
  • 打赏
  • 举报
回复
中国剩余数定理解法
#include <stdio.h>
#include <assert.h>
#include <string.h>
#define DEBUG
#ifdef DEBUG
#include <time.h>
#endif
enum{LEN=32};
// a+=b
void add(unsigned int*a,size_t *asz,const unsigned int*b,size_t bsz);
// a*=b
void mul(unsigned int*a,size_t *size,unsigned long long b);
// a%=b
void rem(unsigned int *a,size_t *asz,const unsigned int*b,size_t bsz);
// ax+by=g -> return x
unsigned long long exgcd(const unsigned int*a,size_t size,unsigned long long b);
int main()
{
    unsigned long long mi[8],ai[8],result;
    unsigned int Mi[8][LEN],M[LEN];
    size_t i,j,Mi_size[8]={0},M_size=0;
#ifdef DEBUG
    clock_t tim;
#endif
    for(i=0;i<8;++i)
        scanf("%llu",mi+i);
    for(i=0;i<8;++i)
        scanf("%llu",ai+i);
#ifdef DEBUG
    tim=clock();
#endif
    for(i=0;i<8;++i)
        mul(M,&M_size,mi[i]);
    for(i=0;i<8;++i)
        for(j=0;j<8;++j)
            if(i!=j)
                mul(Mi[i],Mi_size+i,mi[j]);
    for(i=0;i<8;++i)
    {
        unsigned long long x=exgcd(Mi[i],Mi_size[i],mi[i]);
        mul(Mi[i],Mi_size+i,x);
        mul(Mi[i],Mi_size+i,ai[i]);
    }
    for(i=1;i<8;++i)
        add(Mi[0],Mi_size,Mi[i],Mi_size[i]);
    rem(Mi[0],Mi_size,M,M_size);
    assert(Mi_size[0]<=2);
    switch(Mi_size[0])
    {
        case 0:result=0;break;
        case 1:result=Mi[0][0];break;
        case 2:result=*(unsigned long long*)Mi[0];break;
    }
    if(M_size<=2)
    {
        for(i=1;i<8;++i)
            if(mi[0]<mi[i])
                mi[0]=mi[i];
        if(result<mi[0])
        {
            unsigned long long MM=0;
            switch(M_size)
            {
                case 0:MM=0;break;
                case 1:MM=M[0];break;
                case 2:MM=*(unsigned long long*)M;break;
            }
            result+=MM;
        }
    }
    printf("%llu\n",result);
#ifdef DEBUG
    printf("time:%gs\n",(double)(clock()-tim)/CLOCKS_PER_SEC);
#endif
    return 0;
}
void add(unsigned int*a,size_t *asz,const unsigned int*b,size_t bsz)
{
    unsigned int v[LEN]={0};
    size_t vsz=0;
    unsigned long long r=0;
    while(vsz<*asz||vsz<bsz)
    {
        if(vsz<*asz)
            r+=a[vsz];
        if(vsz<bsz)
            r+=b[vsz];
        v[vsz++]=(unsigned int)r;
        r>>=32;
    }
    if(r)
        v[vsz++]=(unsigned int)r;
    memcpy(a,v,sizeof v);
    *asz=vsz;
    assert(*asz<LEN);
}
void mul(unsigned int*a,size_t *size,unsigned long long b)
{
    unsigned long long r=0;
    size_t i;
    if(!*size)
    {
        *(unsigned long long*)a=b;
        *size=b>>32?2:1;
    }
    else if(b>>32)
    {
        unsigned long long c=(unsigned int)b;
        b>>=32;
        for(i=0;i<*size;++i)
        {
            unsigned int t[3]={0};
            *(unsigned long long*)t=a[i]*c+(r&-1U);
            *(unsigned long long*)(t+1)+=a[i]*b+(r>>32);
            a[i]=t[0];
            r=*(unsigned long long*)(t+1);
        }
        if(r)
        {
            *(unsigned long long*)(a+*size)=r;
            *size+=r>>32?2:1;
        }
    }
    else
    {
        for(i=0;i<*size;++i)
        {
            r+=a[i]*b;
            a[i]=(unsigned int)r;
            r>>=32;
        }
        if(r)
            a[(*size)++]=(unsigned int)r;
    }
    assert(*size<LEN);
}
void rem(unsigned int *a,size_t *asz,const unsigned int*b,size_t bsz)
{
    unsigned int r[LEN];
    size_t rsz=0,l=*asz<<5,i;
    while(l--)
    {
        if(!rsz)
        {
            if(a[l>>5]>>(l&31)&1)
                r[rsz++]=1;
        }
        else
        {
            i=rsz-1;
            if(r[rsz-1]>>31)
                r[rsz++]=1;
            while(i)
            {
                r[i]=r[i]<<1|r[i-1]>>31;
                --i;
            }
            r[0]=(r[0]<<1)|((a[l>>5]>>(l&31))&1);
        }
        if(rsz>bsz)
        {
            for(i=bsz;i;--i)
               *(unsigned long long*)(r+i-1)-=b[i-1];
            while(rsz&&!r[rsz-1]) --rsz;
        }
        else if(rsz&&rsz==bsz)
        {
            for(i=rsz;i&&r[i-1]==b[i-1];--i);
            if(!i||r[i-1]>b[i-1])
            {
                r[rsz-1]-=b[bsz-1];
                for(i=rsz-1;i;--i)
                    *(unsigned long long*)(r+i-1)-=b[i-1];
                while(rsz&&!r[rsz-1]) --rsz;
            }
        }
    }
    memcpy(a,r,sizeof r);
    *asz=rsz;
    assert(*asz<LEN);
}
unsigned long long exgcd(const unsigned int*a,size_t size,unsigned long long b)
{
    long long x[2]={0,1};
    unsigned long long aa=b,bb=0,r;
    if(1==size)
        bb=a[0]%b;
    else
    {
        unsigned int tmp[LEN];
        size_t tsz=size;
        memcpy(tmp,a,sizeof tmp);
        rem(tmp,&tsz,(unsigned int*)&b,b>>32?2:1);
        assert(tsz<=2);
        switch(tsz)
        {
            case 0:bb=0;break;
            case 1:bb=*tmp;break;
            case 2:bb=*(unsigned long long*)tmp;break;
        }
    }
    do
    {
        long long t=x[0];x[0]=x[1];x[1]=t-aa/bb*x[0];
        r=aa%bb;aa=bb;bb=r;
    }while(bb);
    if(x[0]>=0)
        return (unsigned long long)x[0];
    else
        return (unsigned long long)((long long)b+x[0]);
}
附测试数据和结果
2 3 5 7 11 13 17 19
1 1 1 1 1 1 1 1
9699691
time:5.7e-05s
9223372036854775399 9223372036854775417 9223372036854775421 9223372036854775433 9223372036854775507 9223372036854775549 9223372036854775643 9223372036854775783
408 390 386 374 300 258 164 24
9223372036854775807
time:0.000285s
4294967111 4294967143 4294967161 4294967189 4294967197 4294967231 4294967279 4294967291
2147500667 2147495275 2147492692 2147489318 2147488498 2147485727 2147483783 2147483657
9223372036854775807
time:0.000137s
4294967111 4294967143 4294967161 4294967189 4294967197 4294967231 4294967279 4294967291
400879708 76365989 2309746472 1488927345 2481541213 2405183635 4065902492 1259857083
8690466096661279830
time:0.000127s
c090869 2015-11-01
  • 打赏
  • 举报
回复
7+3m=7+5n, 3m=5n, m肯定有5的因子, n肯定有3的因子。
伊顺鸣 2015-11-01
  • 打赏
  • 举报
回复
qinfeng0701 2015-11-01
  • 打赏
  • 举报
回复
网上搜了一下中国剩余数定理,数学原理告诉我们定域内解是唯一的。 至少有6种解法,其中至少三种符合楼主的要求。 我的这种是逐级求解法,计算时间还是长了,有不用循环,直奔答案的解法。
qinfeng0701 2015-11-01
  • 打赏
  • 举报
回复
d2 := a1*a2; n := (d2*i + c2) mod a3; 为什么要用前面数的最小公倍数做基数,为什么一个基数倍域范围内只有只一个解,这里我用的是经验公式,数学原理也不清楚。
qinfeng0701 2015-11-01
  • 打赏
  • 举报
回复
07年的明基笔记本跑不出毫秒级时差
  StartTime:=GetTickCount;
  a1:=2; a2:=3; a3:=5; a4:=7; a5:=11; a6:=13; a7:=17; a8:=19;
  b1:=1; b2:=1; b3:=1; b4:=1;  b5:=1;  b6:=1; b7:=1;  b8:=1;
  for i := 1 to a2 do
  begin
    n := (a1*i + b1) mod a2;
    if n = b2 then
    begin
      c2 := a1*i + b1;
      d2 := a1*a2;
      break;
    end;
  end;
  //i = 3  c2 = 7
  for i := 1 to a3 do
  begin
    n := (d2*i + c2) mod a3;
    if n = b3 then
    begin
      c3 := d2*i + c2;
      d3 := d2*a3;
      break;
    end;
  end;
  //i = 4 c3 = 31
  for i := 1 to a4 do
  begin
    n := (d3*i + c3) mod a4;
    if n = b4 then
    begin
      c4 := d3*i + c3;
      d4 := d3*a4;
      break;
    end;
  end;
  //i = 6 c4=211
  for i := 1 to a5 do
  begin
    n := (d4*i + c4) mod a5;
    if n = b5 then
    begin
      c5 := d4*i + c4;
      d5 := d4*a5;
      break;
    end;
  end;
  //i = 10 c5=2311
  for i := 1 to a6 do
  begin
    n := (d5*i + c5) mod a6;
    if n = b6 then
    begin
      c6 := d5*i + c5;
      d6 := d5*a6;
      break;
    end;
  end;
  //i = 12 c6=30031
  for i := 1 to a7 do
  begin
    n := (d6*i + c6) mod a7;
    if n = b7 then
    begin
      c7 := d6*i + c6;
      d7 := d6*a7;
      break;
    end;
  end;
  //i = 16 c7=510511
  for i := 1 to a8 do
  begin
    n := (d7*i + c7) mod a8;
    if n = b8 then
    begin
      c8 := d7*i + c7;
      d8 := d7*a8;
      break;
    end;
  end;
  //i = 18; c8=9699691
  EndTime:=GetTickCount;
qinfeng0701 2015-11-01
  • 打赏
  • 举报
回复
求最小值,共循环57次,算法分解,一目了然
  a1:=3; a2:=5; a3:=7; a4:=13; a5:=17; a6:=19; a7:=23; a8:=29;
  b1:=1; b2:=2; b3:=4; b4:=6;  b5:=2;  b6:=10; b7:=1;  b8:=11;
  for i := 1 to a2 do
  begin
    n := (a1*i + b1) mod a2;
    if n = b2 then
    begin
      c2 := a1*i + b1;
      d2 := a1*a2;
      break;
    end;
  end;
  //i = 2  c2 = 7
  for i := 1 to a3 do
  begin
    n := (d2*i + c2) mod a3;
    if n = b3 then
    begin
      c3 := d2*i + c2;
      d3 := d2*a3;
      break;
    end;
  end;
  //i = 4 c3 = 67
  for i := 1 to a4 do
  begin
    n := (d3*i + c3) mod a4;
    if n = b4 then
    begin
      c4 := d3*i + c3;
      d4 := d3*a4;
      break;
    end;
  end;
  //i = 4 c4=487
  for i := 1 to a5 do
  begin
    n := (d4*i + c4) mod a5;
    if n = b5 then
    begin
      c5 := d4*i + c4;
      d5 := d4*a5;
      break;
    end;
  end;
  //i = 5 c5=7312
  for i := 1 to a6 do
  begin
    n := (d5*i + c5) mod a6;
    if n = b6 then
    begin
      c6 := d5*i + c5;
      d6 := d5*a6;
      break;
    end;
  end;
  //i = 18 c6=425002
  for i := 1 to a7 do
  begin
    n := (d6*i + c6) mod a7;
    if n = b7 then
    begin
      c7 := d6*i + c6;
      d7 := d6*a7;
      break;
    end;
  end;
  //i = 2 c7=1306792
  for i := 1 to a8 do
  begin
    n := (d7*i + c7) mod a8;
    if n = b8 then
    begin
      c8 := d7*i + c7;
      d8 := d7*a8;
      break;
    end;
  end;
  //i = 22; c8=224399662
qinfeng0701 2015-10-31
  • 打赏
  • 举报
回复
for(k=mn/(a[i]-1),s=0,ab=0;ab<=mn;k++)范围太大 15X+7=7Y+4<15*7 过滤掉了绝大部分的不可能数据
qinfeng0701 2015-10-31
  • 打赏
  • 举报
回复
我是逐位求,你得是直接来八个,这样逐个计算太浪费。
加载更多回复(19)

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧