(1)
从自然数1,2,…,n,从中任取r个数,输出所有组合。
输入格式
一行两个自然数n、r(1<n<21,1≤r≤n)。
输出格式
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
输入样例
5 3
输出样例
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
这道题很简单,一般思想都是初始化数字为最小 (记录各个位最小值)然后从个位开始改变不能变了将个位最小值+1 个位变为此最小值 十位+1
十位同理
当第一位递增超过r时结束
这里不用此一般方法,有搜索递归进行演示
#include<cstdio>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<cstdlib>
using namespace std;
const double eps=1e-8;
const int MAX=0x3f3f3f3f;
int n;
int a[1000010];
int t;
void bfs(int begi,int n,int r,int sum)//当前取数范围 将要选取数字个数 已选取个数
{
if(n<r)
return ;
if(sum>t)
{
for(int i=0;i<t;i++)
{
cout<<setw(3)<<a[i];
}
cout<<endl;
}
else
{
for(int i=begi;i<=n;i++)
{
a[sum-1]=i;
bfs(i+1,n,r,sum+1);
}
}
}
int main()
{
int n,r;
cin>>n>>r;
t=r;
bfs(1,n,r,1);
return 0;
}
(2)
任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。
当n=7共14种拆分方法:参考输出样例
输入格式
输入有多组数据,每组数据一行,每行给出一个正整数n(2<=n<=20)。
输出格式
对于每组数据输出若干行,参考样例。
相邻两组样例之间输出一个空行。
输入样例
2
7
输出样例
2=1+1
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string.h>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const int MAX=0x3f3f3f3f;
int a[1000010]= {1};
int t;
int n,r;
void dfs(int sum,int step)
{
for(int i=a[step-1]; i<=sum; i++)
{
if(i<n)//保证按字典序
{
a[step]=i;
sum-=i;
//以上两步连起来看 将末尾添加一个i
//用剩余数减去此i
//为0继续打印就好
//为负不满足字典序被if 排除 返回上一层
//余数恢复
//i++ 保证字典序
//周而复始
if(sum==0)
{
int f=0;
cout<<t<<"=";
for(int i=1;i<=step;i++)
{
if(f)
cout<<"+";
cout<<a[i];
f=1;
}
cout<<endl;
}
else
dfs(sum,step+1);
sum+=i;//恢复
}
}
}
int main()
{
cin>>n;
t=n;
dfs(n,1);
//cout<<endl;
while(cin>>n)
{
t=n;
cout<<endl;
dfs(n,1);
}
return 0;
}
这道题不算简单细节比较多
结合输出来说下原理(虽然好像已近在代码里面了)
本质上就是凑余数
打印条件是余数为0
期间控制字典序(i的递增,i的判断)
由于一开始num余数为最大
且初始化为1
可以得到初始为全1的结果
打印后递归返回 余数复位
位数被动-1 (因为从step+1的递归退出)
将该数赋值为i继续试减
调试代码:
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string.h>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const int MAX=0x3f3f3f3f;
int a[1000010]= {1};
int t;
int n,r;
void dfs(int sum,int step)
{
for(int i=a[step-1]; i<=sum; i++)
{
if(i<n)//保证按字典序
{
a[step]=i;
sum-=i;
if(sum==0)
{
cout<<" if 进入 ";
int f=0;
cout<<t<<"=";
for(int i=1; i<=step; i++)
{
if(f)
cout<<"+";
cout<<a[i];
f=1;
}
cout<<endl;
}
else
{
cout<<"else 进入 ";
int f=0;
cout<<t<<"=";
for(int i=1; i<=step; i++)
{
if(f)
cout<<"+";
cout<<a[i];
f=1;
}
cout<<endl;
dfs(sum,step+1);
}
sum+=i;//恢复
}
}
}
int main()
{
cin>>n;
t=n;
dfs(n,1);
//cout<<endl;
while(cin>>n)
{
t=n;
cout<<endl;
dfs(n,1);
}
return 0;
}
一目了然
(3)
输入正整数n,把整数1,2,...,n组成一个环,使得相邻两个整数之和均为素数。输出时,从整数1开始逆时针排列。同一个环恰好输出一次。
输入格式
输入存在多组测试数据,每组测试数据输入一个正整数n(n<=16)
输出格式
输出的时候第i组测试数据输出Case i:
然后输出若干行,每一行n个数字表示素数环,由于每个环只输出一次,也就是第一个数字永远是1
按照第二位从小到大,第二位相同第三位从小到大,以此类推输出所有方案
相邻两组测试数据之间输出一个空行
输入样例
6
8
输出样例
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
这道题太难优化了,这是1s能完成的程序????????????
我整个计算机都在响
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string.h>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-8;
const int MAX=0x3f3f3f3f;
int n,r;
int a[110];
int used[20];
int sum=1;
int prime[20]={0,2,3,5,7,11,13,17,19,23,29,31};
//从prime[1]-[11]
int ispre(int x)
{
/*
for(int k=2; k<=sqrt(x); k++)
if(x%k==0)
{
// cout<<"不是素数"<<endl;
return 0;
}
// cout<<"是素数"<<endl;
return 1;
*/
//int f=0;
for(int k=1;k<=11;k++)
{
//速度应该还会慢
if(x==prime[k])
return 1;
}
return 0;
}
void bfs(int x)
{
//cout<<"进入"<<endl;
for(int i=2; i<=n; i++)
{
if((!used[i])&&ispre(a[x-1]+i))
{
used[i]=1;
a[x]=i;
//cout<<"筛选成功一个"<<endl;
//cout<<"当前x n ="<<x<<" "<<n<<endl;
//cout<<"最后一个值"<<a[n]<<endl;
if((x==n)&&ispre(1+a[n]))
{
//打印
//cout<<"进入打印"<<endl;
int f=0;
for(int j=1; j<=n; j++)
{
if(f)
cout<<" ";
cout<<a[j];
f=1;
}
cout<<endl;
}
else
{
// cout<<"进入下一层"<<endl;
bfs(x+1);
}
used[i]=0;
}
//cout<<"下一个"<<endl;
}
}
int main()
{
/*for(int i=2;i<=100;i++)
{
if(ispre(i))
cout<<i<<" ";
}*/
//system("pause");
// initialize();
cin>>n;
int sum=1;
memset(a,0,sizeof(a));
memset(used,0,sizeof(used));
a[1]=1;
used[1]=1;
cout<<"Case "<<sum<<":"<<endl;
sum++;
bfs(2);
while(cin>>n)
{
cout<<endl;
cout<<"Case "<<sum<<":"<<endl;
sum++;
int sum=1;
memset(a,0,sizeof(a));
memset(used,0,sizeof(used));
a[1]=1;
used[1]=1;
bfs(2);
}
return 0;
}
先放这里吧,以后再看看
注意在搜索题中临时变量一般用局部变量,
这样可以避免一些改变计数变量的小问题
22.02.16更新
尝试了一下埃氏筛,貌似也不行
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string.h>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-8;
const int MAX=0x3f3f3f3f;
int n,r;
int a[110];
int used[20];
int sum=1;
int prime[32]={0};
//从prime[1]-[11]
void initialize()//埃氏筛
{
fill(prime,prime+32,1);
//memset(prime,1,sizeof(a));
//for(int i=3;i<=32;i++)
// prime[i]=1;
prime[0]=prime[1]=0;
for(int i=2;i<=32;i++)
{
if(prime[i])
{
for(int j=2*i;j<=32;j+=i)
prime[j]=0;
}
}
}
/*
int ispre(int x)//普通素数判断
{
/*
for(int k=2; k<=sqrt(x); k++)
if(x%k==0)
{
// cout<<"不是素数"<<endl;
return 0;
}
// cout<<"是素数"<<endl;
return 1;
//int f=0;
for(int k=1;k<=11;k++)
{
//速度应该还会慢
if(x==prime[k])
return 1;
}
return 0;
*/
void bfs(int x)
{
//cout<<"进入"<<endl;
for(int i=2; i<=n; i++)
{
if((!used[i])&&prime[a[x-1]+i])
{
used[i]=1;
a[x]=i;
//cout<<"筛选成功一个"<<endl;
//cout<<"当前x n ="<<x<<" "<<n<<endl;
//cout<<"最后一个值"<<a[n]<<endl;
// if((x==n)&&ispre(1+a[n]))
if((x==n)&&prime[1+a[n]])
{
//打印
//cout<<"进入打印"<<endl;
int f=0;
for(int j=1; j<=n; j++)
{
if(f)
cout<<" ";
cout<<a[j];
f=1;
}
cout<<endl;
}
else
{
// cout<<"进入下一层"<<endl;
bfs(x+1);
}
used[i]=0;
}
//cout<<"下一个"<<endl;
}
}
int main()
{
/*for(int i=2;i<=100;i++)
{
if(ispre(i))
cout<<i<<" ";
}*/
//system("pause");
initialize();
/*
for(int i=1;i<=32;i++)
{
cout<<prime[i]<<" ";
}
cout<<endl;
*/
cin>>n;
int sum=1;
memset(a,0,sizeof(a));
memset(used,0,sizeof(used));
a[1]=1;
used[1]=1;
cout<<"Case "<<sum<<":"<<endl;
sum++;
bfs(2);
while(cin>>n)
{
cout<<endl;
cout<<"Case "<<sum<<":"<<endl;
sum++;
int sum=1;
memset(a,0,sizeof(a));
memset(used,0,sizeof(used));
a[1]=1;
used[1]=1;
bfs(2);
}
return 0;
}