P1008 [NOIP1998 普及组] 三连击

注:本题掌握后可继续做https://www.luogu.com.cn/problem/P1618

一.题目概括

将 1,2,…,9 共 9 个数分成 3 组,分别组成 3 个三位数,且使这 3 个三位数构成 1:2:3 的比例,试求出所有满足条件的 3 个三位数

二.关键点

1.手写全排列:深搜全排列问题

这道题的总体思路就是求出1-9的全排列并将其存在字符串中,分割字符串,求出值(由于不需要输出9的全排列,所以会快很多)

全排列问题是一道很经典的问题,符合深搜的逻辑,精髓是用深搜递归n重循环(深搜复杂度O(n!),本题只有九重,所以复杂度为9!=362880,不超时),判断不重复,标记后,求出具体的排列

以下是全排列的一个示例dfs代码(已通过洛谷P1706)(字符全排列类似):

void dfs(int step,vector<int> lp){
	if(step==n){
		for(int i=0;i<lp.size();i++)printf("%5d",lp[i]);
		printf("\n");
		return;
	}
	else{
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				vis[i]=true;
				lp.push_back(i);
				dfs(step+1,lp);
				lp.pop_back();
				vis[i]=false;
			}
		}
	}
}
//vis:记录数组 lp:路径
2.algorithm库自带全排列函数

这种方法适合没有时间,或仅仅输出要用全排列的OIer

示例代码如下(已通过洛谷P1706)

函数中的参数和sort函数类似

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<int> vec;
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++)vec.push_back(i+1);
	do{
		for(int i=0;i<vec.size();i++)printf("%5d",vec[i]);
		printf("\n");
	}while(next_permutation(vec.begin(),vec.end()));
}

三.AC代码

1.解法1:手写全排列
#include <iostream>
#include <cstring>
#define N 9
using namespace std;
bool vis['9'+10];
int _atoi(string s){//字符串->int
	int n;
	for(int i=0;i<s.size();i++){
		n=n*10+(s[i]-'0'); //构造int
	}
	return n;
}
void dfs(int step,string s){//step:步数(添加了几个数字),s:路径字符串
	if(step==N){
		int a=_atoi(s.substr(0,3));
		int b=_atoi(s.substr(3,3));
		int c=_atoi(s.substr(6,3));
		if(2*a==b&&a*3==c)cout<<a<<' '<<b<<' '<<c<<endl;
		return;
	}
	else{
		for(char i='1';i<='9';i++){
			if(!vis[i]){	
				vis[i]=true;//标记
				dfs(step+1,s+i);
				vis[i]=false;
			}
		}
	}
}
int main(){
	dfs(0,"");
}

时间:

2.解法2:algorithm全排列
#include <iostream>
#include <vector>
#include <algorithm>
#define N 9
using namespace std;
vector<int> vec;
int main(){
	for(int i=0;i<N;i++)vec.push_back(i+1);
	do{
		int a=vec[0]*100+vec[1]*10+vec[2];
		int b=vec[3]*100+vec[4]*10+vec[5];
		int c=vec[6]*100+vec[7]*10+vec[8];
		if(a*2==b&&a*3==c)cout<<a<<' '<<b<<' '<<c<<endl;
	}while(next_permutation(vec.begin(),vec.end()));
}

时间:

四.直达链接

https://www.luogu.com.cn/problem/P1008

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值