P1618 三连击(升级版)

原题地址:https://www.luogu.com.cn/problem/P1618

题目描述:将 1, 2,9 共 9 个数分成三组,分别组成三个三位数,且使这三个三位数的比例是 A:B:C,试求出所有满足条件的三个三位数,若无解,输出 No!!!

输入格式:三个数,A,B,C

输出格式:若干行,每行 3 个数字。按照每行第一个数字升序排列。

 

一开始的思路是打表从一个存储123456789的数组里直接选数,保证选完的不再选(可以用一个bool数组存放“是否已选”),但我不会搜索、动态规划什么的,逻辑能力十分弱,这种解法真的想不出来。

这里要感谢大佬 可耐滴小慕容 (主页->)https://www.luogu.com.cn/user/24663#main的题解,ta启发了我的新思路(我真的没抄袭复制!所有代码都是我自己写的!只是ta的思路启发了我!这应该不算抄袭吧!)

可以直接枚举第一个数,根据比例算出来另外两个数,再进行判断!(这句话是大佬的知识产权)

首先设计出判断数字位数和获取数字某一位的数字的函数,以备之后使用:

int getCertainNumOfInt(int a,int num)//返回数字串a的第num位数(从右往左数)。
{
    int ten=1,q;
    for(q=1;q<num;q++)
    {
        ten*=10;
    }
    int r=a/ten%10;
    return r;
}

int get_length(int a)//返回数字a的位数。
{
    int leng=0;
    while(a)
    {
        a/=10;
        leng++;
    }
    return leng;
}

然后是存储1—9数字是否用过的数组:

int p[10]={0,0,0,0,0,0,0,0,0,0};

(p[0]纯属占位)

然后,判断一个三位数本身是否重复的函数(自己就重复就肯定不对了)

bool isNoRepeat(int a)
{
    int ge=a%10;//个位数 
    int bai=a/100;//百位数 
    int shi=(a/10)%10;//十位数 
    if(ge==bai||ge==shi||bai==shi) return false;//只要有相同的数就不满足条件 
    else return true;
}

接着是判断三个三位数的数字是否互不重复:

bool isAllNoRepeat(int a,int b,int c)
{
    if(!(isNoRepeat(a)&&isNoRepeat(b)&&isNoRepeat(c))) return false;//只要自身重复了就不对
    else
    {
        for(int i=1;i<=3;i++)
        {
            p[getCertainNumOfInt(a,i)]++;
        }
        for(int i=1;i<=3;i++)
        {
            p[getCertainNumOfInt(b,i)]++;
        }
        for(int i=1;i<=3;i++)
        {
            p[getCertainNumOfInt(c,i)]++;
        }
    }
    for(int i=1;i<10;i++)
    {
        if(p[i]!=1)//有0代表有的数字没选,有大于一的数字代表有的数字选了多次,都不对
        {
            memset(p,0,sizeof(p));//别忘了原数组清零,供下一次使用
            return false;
        }
    }
    memset(p,0,sizeof(p));//别忘了原数组清零,供下一次使用
    return true;                
}

以下是main的第一版代码(不对的一版):

int main()
{
    int a,b,c;
    cin>>a>>b>>c;
    int x,y,z;//存放根据比例算出的三个三位数
    int tot=0;
    for(int i=100;i<=999;i++)
    {
        if(!isNoRepeat(i)) continue;//自己要不重复
        x=i;
        y=x/a*b;//潜在问题
        z=x/a*c;//潜在问题
        if(x<1000&&y<1000&&z<1000/*必须是三位数*/&&isAllNoRepeat(x,y,z))
        {
            cout<<x<<" "<<y<<" "<<z<<endl;
            tot++;
        }
    }
    if(!tot) cout<<"No!!!";//没有答案
    return 0;
}

注意到潜在问题了吗?可能有极特殊的情况,由于xyz的精度不高,可能算不出精确的三位数!最后,这种代码导致了一个监测点WA。

第二版代码:

int main()
{
    int a,b,c;
    cin>>a>>b>>c;
    double x,y,z;
    int tot=0;
    for(int i=100;i<=999;i++)
    {
        if(!isNoRepeat(i)) continue;
        x=(double)i;
        y=x/(double)a*b;
        z=x/(double)a*c;
        if(x<1000&&y<1000&&z<1000&&isAllNoRepeat(x,y,z))
        {
            cout<<x<<" "<<y<<" "<<z<<endl;
            tot++;
        }
    }
    if(!tot) cout<<"No!!!";
    return 0;
}

double换取了更高的精度,算出的数字排除了特殊情况。全部AC!

这个题让我学到了:1.换一种思路!方法总比困难多!

2.用除法的时候要特别考虑精度(即用int还是double)

posted @ 2020-02-04 22:38  梦中霜雪梨花白  阅读(203)  评论(0编辑  收藏  举报