洛谷 P1618 三连击(升级版)【DFS/next_permutation()/技巧性枚举/sprintf】

【链接】:https://www.luogu.org/problemnew/show/P1618

题目描述

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

//感谢黄小U饮品完善题意

输入输出格式

输入格式:

三个数,A B C。

输出格式:

若干行,每行3个数字。按照每行第一个数字升序排列。

输入输出样例

输入样例#1:
复制

1 2 3

输出样例#1: 复制

192 384 576
219 438 657
273 546 819
327 654 981

说明

保证A<B<C

【分析】:

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
    int a,b,c,num,i1,i2,i3,flag=0;
    cin>>i1>>i2>>i3;
    for(num=1;num<=999;num++){
        a=i1*num;b=i2*num;c=i3*num;
        if((a/100+a/10%10+a%10+b/100+b/10%10+b%10+c/100+c/10%10+c%10==45)&&((a/100)*(a/10%10)*(a%10)*(b/100)*(b/10%10)*(b%10)*(c/100)*(c/10%10)*(c%10)==362880)){
            cout<<a<<" "<<b<<" "<<c<<endl;
            flag=1;
        }
    }
    if(flag==0){
        cout<<"No!!!";
    }
    return 0;

} 

普通枚举

1.

枚举每一个可能的数,将三个倍数保存在数组中,再排序,最后通过和标准的“123456789”比较,如果相同,则满足条件。这样用一个常量数组,可以简化计算,不需要过多的思考。所以说常量数组大法真的好~因为之前做过三连击的简单版,就有了思维定式,枚举总是从123开始,所以最后一个(数据是123 456 789)总是错。最后一个过不去的同学可以试试从1开始枚举,就会过去了。

#include <bits/stdc++.h>

using namespace std;

char stdanard[]="123456789";

int a,b,c;

int main()
{
    int flag=1;
    cin>>a>>b>>c;
    for(int i=1;i<=999;i++)
    {
        char buf[20];//开大防止溢出
        sprintf(buf,"%d%d%d",a*i,b*i,c*i);
        sort(buf,buf+9);
        if(strcmp(stdanard,buf)==0)
        {
            flag=0;
            printf("%d %d %d\n",a*i,b*i,c*i);
        }
    }
    if(flag) puts("No!!!");
    return 0;
}

sprintf

2.我和大部分人思路基本一样,不一样的地方在于对三个数组成的9个数的拆分上,我用的是sstream头文件,将三个数放到一个字符串中去,这样就不用%或者/去费力拆分了,写起来更优雅,然后将字符串每个数加起来 乘起来,即可验证是否为不同的9个数。

/*
对三个数组成的9个数的拆分上,用的是sstream头文件,
将三个数放到一个字符串中去,
这样就不用%或者/去费力拆分了,写起来更优雅,
然后将字符串每个数加起来 乘起来,即可验证是否为不同的9个数。
*/
#include <bits/stdc++.h>

using namespace std;

stringstream ss;
string str;
int cnt=0;
int a,b,c;

int main()
{
    cin>>a>>b>>c;

    for(int i=123;i<=329;i++)
    {
        int j=i*b/a;
        int k=i*c/a;
        int sum=0;
        int pro=1;
        ss<<i<<j<<k;
        ss>>str;
        ss.clear();

        for(int j=0;j<9;j++)
        {
            sum+=str[j]-‘0‘;
            pro*=str[j]-‘0‘;
        }

        if(sum==45 && pro==362880)
        {
            cout<<i<<" "<<j<<" "<<k<<" "<<endl;
            cnt++;
        }

    }
    if(!cnt) puts("No!!!");
    return 0;
}

stringstream

3.

/*
其实判断是否相等不需要if(a==b&&b==c...)这样乱七八糟的打一大坨,一个数组就能完成。如下:
*/
#include <bits/stdc++.h>

using namespace std;

int d[10];//数组d判断位数是否相等。
int main()
{
    float x,y,z;
    int a,b,c,t=0,j=0;//j判断是否有解
    cin>>x>>y>>z;//即A、B、C
    for(a=100;a<=999;a++)//枚举最小的那个数
    {
        b=y*a/x;
        c=z*a/x;
        d[a/100]++;
        d[(a%100)/10]++;
        d[a%10]++;

        d[b/100]++;
        d[(b%100)/10]++;
        d[b%10]++;

        d[c/100]++;
        d[(c%100)/10]++;
        d[c%10]++;
        for(int bb=1;bb<=9;bb++)
        {
            if(d[bb]==0) t=1;//由于总共只有九个数字,若有一个数没有出现,就说明有数字重复了。
            d[bb]=0;//归零
        }
        if(t==0) {cout<<a<<" "<<b<<" "<<c<<endl;j=1;}//若有解,输出a、b、c
        t=0;
    }
    if(!j) cout<<"No!!!";
    return 0;
}

数组技巧性枚举

# include <stdio.h>
# define MUL(x) (x%10)*(x/10%10)*(x/100)            //一个三位数x所包含的3个数的乘积为MUL(x)
# define ADD(x) (x%10)+(x/10%10)+(x/100)            //一个三位数x所包含的3个数的总和为ADD(x)
const product=1*2*3*4*5*6*7*8*9;                    //数字1—9的乘积为product
const int sum=1+2+3+4+5+6+7+8+9;                    //数字1—9的总和为sum
int main()
{
    int A,B,C,a=0,Yes=0;                            //变量Yes用于检测是否有解
    scanf("%d %d %d",&A,&B,&C);                        //输入3个三位数的比例A:B:C(A<B<C且为最简比)
    while(++a*A<100);                                //保证这3个数中最小的数是三位数
    for(;a*C<1000;a++)                                //保证这3个数中最大的数是三位数
        if(product==MUL(a*A)*MUL(a*B)*MUL(a*C)        //倘若它们所包含的9个数的乘积恰好为product
            && sum==ADD(a*A)+ADD(a*B)+ADD(a*C))        //并且总和恰好为sum时,说明没有重复数字和0
            Yes=printf("%i %i %i\n",a*A,a*B,a*C);    //输出这3个由1—9组成的三位数,并给Yes赋值
    if(!Yes)                                        //若无解
        puts("No!!!");                                //则输出“No!!!”
    return 0;
}

技巧性枚举

4.

#include<iostream>
using namespace std;
int x[10]={0},a,b,c; //x[1]~x[9]为当前位置的数字 先把三个三位数合成一个9(10)位数的大数组
bool used[10]={0},ans=false;
//used数组表示该数字的使用情况 避免重复   ans判断是否有答案
int cons(int m){   //将数组拆分成三个三位数
    int sum=0;
    for(int i=3*m-2;i<=3*m;i++){
        sum*=10;
        sum+=x[i];
    }
    return sum;
}
void solve(int n){
    if(n==10&&cons(1)*b==cons(2)*a&&cons(1)*c==cons(3)*a){   //当n=10时x数组数字存满 开始判断
        cout<<cons(1)<<" "<<cons(2)<<" "<<cons(3)<<endl;
        ans=true;
        return;
    }
    for(int i=1;i<=9;i++){
        if(!used[i]){
            x[n]=i;   //存数字
            used[i]=1;   //该数字被使用
            solve(n+1);  //下一位继续调用
            used[i]=0;  //恢复
        }
    }
    return;
}
int main(){
    cin>>a>>b>>c;
    solve(1);  //开始搜索
    if(!ans) cout<<"No!!!";  //ans!=true即输出"No!!!"
    return 0;
}

DFS

5.STL中的next_permutation函数提供下一个排列功能,是用生成法实现的,所以速度要比搜索快多了。

#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int main()
{
    int A,B,C,h=0;
    cin>>A>>B>>C;
    int t=A*B*C;
    A=t/A;
    B=t/B;
    C=t/C;
    do{
        if((100*a[1]+10*a[2]+a[3])*A==(100*a[4]+10*a[5]+a[6])*B&&(100*a[1]+10*a[2]+a[3])*A==(100*a[7]+10*a[8]+a[9])*C)//如果符合比例;
        {
            cout<<a[1]<<a[2]<<a[3]<<" "<<a[4]<<a[5]<<a[6]<<" "<<a[7]<<a[8]<<a[9]<<endl;//输出
            h++;
        }
    }while(next_permutation(a+1,a+10));//STL中的下一个排列函数;
    if(h==0) cout<<"No!!!";//没有解输出NO;
    return 0;
}

next_permutation()

#include<iostream>
#include<algorithm>
using namespace std;
int a[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
bool isSame(int v[], int a[]) {
    for (int i = 0; i != 3; i++)
        if (v[i] != a[i])
            return false;
    return true;
}
int main()
{
    int A, B, C;
    int visit[3] = { 0 };
    int pos;
    bool flag = false;
    cin >> A >> B >> C;
    do {
        int x = a[0] * 100 + a[1] * 10 + a[2];
        int y = a[3] * 100 + a[4] * 10 + a[5];
        int z = a[6] * 100 + a[7] * 10 + a[8];
        int a[3] = { x, y, z };
        sort(a, a + 3);
        if (!isSame(visit, a)) {
            if ((double)y / x == (double)B / A && (double)z / x == (double)C / A && (double)z / y == (double)C / B) {
                cout << a[0] << " " << a[1] << " " << a[2] << endl;
                flag = true;
            }
        }
    } while (next_permutation(a, a + 9));
    if (flag == false)
        cout << "No!!!" << endl;
    return 0;
}

5.2

原文地址:https://www.cnblogs.com/Roni-i/p/8277327.html

时间: 2024-11-08 02:14:57

洛谷 P1618 三连击(升级版)【DFS/next_permutation()/技巧性枚举/sprintf】的相关文章

洛谷 P1618 三连击(升级版)

题目描述 将1,2,…,9共9个数分成三组,分别组成三个三位数,且使这三个三位数的比例是A:B:C,试求出所有满足条件的三个三位数,若无解,输出“No!!!”. //感谢黄小U饮品完善题意 输入输出格式 输入格式: 三个数,A B C. 输出格式: 若干行,每行3个数字.按照每行第一个数字升序排列. 输入输出样例 输入样例#1: 1 2 3 输出样例#1: 192 384 576 219 438 657 273 546 819 327 654 981 说明 保证A<B<C 全排列式 枚举 屠龙

洛谷P1120小木棍[DFS]

题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度. 输入输出格式 输入格式: 输入文件共有二行. 第一行为一个单独的整数N表示砍过以后的小木棍的总数,其中N≤60 (管理员注:要把超过50的长度自觉过滤掉,坑了很多人了!) 第二行为N个用空个隔开的正整数,表示N根小木棍的长度. 输出格式: 输出文件仅一行,表示要求

洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)

To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N move from the barn to her private pasture. The pastures are organized as a tree, with the barn being on pasture 1. Exactly N-1 cow

洛谷 P1219 八皇后【经典DFS,温习搜索】

P1219 八皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下: 行号 1 2 3 4 5 6 列号 2 4 6 1 3 5 这只是跳棋放置的一个解.请编一个程序找出所有跳棋放置的解.并把它们以上面的序列方法输出.解按字典顺序排列.请输出前3个解.最后一行是解的总个数. //以下的

洛谷 P1784 数独[DFS/回溯]

To 洛谷.1784 数独类似题:CODEVS.4966 简单数独(4*4数独) CODEVS.2924 数独挑战) 题目描述 数独是根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个粗线宫内的数字均含1-9,不重复.每一道合格的数独谜题都有且仅有唯一答案,推理方法也以此为基础,任何无解或多解的题目都是不合格的. 芬兰一位数学家号称设计出全球最难的“数独游戏”,并刊登在报纸上,让大家去挑战. 这位数学家说,他相信只有“智慧最顶尖”的人才有可能破解这个“数独之谜”.

洛谷 P1019 单词接龙 (DFS)

题目传送门 当时一看到这题,蒟蒻的我还以为是DP,结果发现标签是搜索-- 这道题的难点在于思路和预处理,真正的搜索实现起来并不难.我们可以用一个贪心的思路,开一个dic数组记录每个单词的最小重复部分,这样搜索的时候就可以很方便地查阅dic数组,而不是每次再计算一遍. 预处理是长这样子的: void f(string a,string b,int x,int y) { int a1=a.size()-1,b1=b.size()-1; for(int i=0;i<=b1;i++) //从第一个开始枚

洛谷.1919.[模板]A乘B Problem升级版(FFT)

题目链接:洛谷.BZOJ2179 //将乘数拆成 a0*10^n + a1*10^(n-1) + ... + a_n-1的形式 //可以发现多项式乘法就模拟了竖式乘法 所以用FFT即可 注意处理进位 //n位*n位最多就只有2n位了 //论putchar的速度..还是快的 #include <cmath> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar

[题解]洛谷比赛『期末考后的休闲比赛2』

[前言] 这场比赛已经结束了有几天,但我各种忙,虽然AK但还是没来得及写题解.(我才不会告诉你我跑去学数据结构了) T1 区间方差 (就不贴题好了) 首先可以推公式(我们可以知道,线段树然而并不能通过初中学过的方差公式在log(L)内求出方差): (s2表示方差,L表示区间长度,xi表示区间的每一项,最后一个x上画了一根线表示这些数据的平均数) 用二项式定理完全平方公式可得: 再次展开: 另外,再代入以下这个 得到了: 然后继续吧.. 然后duang地一声合并同类项,于是我们得到了: 然后可以高

洛谷P2420 让我们异或吧

P2420 让我们异或吧 161通过 450提交 题目提供者该用户不存在 标签洛谷原创云端↑ 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 倍增可做的吧 玄学 更改根节点得分不一样- 这题面似乎对一些群体不太友- 这题为什么没数据 C++选手注意了 题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中-xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是否是男生)=A和B是否能够成为情