P2404 自然数的拆分问题
题目描述
任何一个大于 11 的自然数 n,总可以拆分成若干个小于 n 的自然数之和。现在给你一个自然数 n,要求你求出 n 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
输入格式
输入:待拆分的自然数 n。
输出格式
输出:若干数的加法式子。
输入输出样例
输入 #1复制
7
输出 #1复制
1+1+1+1+1+1+1 1+1+1+1+1+2 1+1+1+1+3 1+1+1+2+2 1+1+1+4 1+1+2+3 1+1+5 1+2+2+2 1+2+4 1+3+3 1+6 2+2+3 2+5 3+4
说明/提示
数据保证,2≤n≤8。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n, a[10];
void dfs(int sum, int t, int z)
{
if(sum > n) return;//当搜索到的总和大于n时,序列不符合条件,中断递归
if(sum == n)//序列满足和等于n时,则按题目格式进行输出
{
printf("%d", a[1]);
for(int i = 2; i < t; i++) printf("+%d", a[i]);
printf("\n");
return;
}
for(int i = z; i < n; i++)//防止输出重复的序列,使序列后一个数总大于前一个数
{
a[t] = i;//给数组a填充i值,作为序列的每个部分
dfs(sum + i, t + 1, i);
}
}
int main()
{
scanf("%d", &n);
dfs(0, 1, 1);
return 0;
}
该题是个典型的dfs问题。最重要的就是熟悉该题dfs的过程并且搞清的dfs()中填入各数的关系。
其他的解释都在注释中。
P2036 [COCI 2008/2009 #2] PERKET
题目描述
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s 和苦度 b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 n,表示可供选用的食材种类数。
接下来 n 行,每行 22 个整数 si 和 bi,表示第 i 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例
输入 #1复制
1 3 10
输出 #1复制
7
输入 #2复制
2 3 8 5 8
输出 #2复制
1
输入 #3复制
4 1 7 2 6 3 8 4 9
输出 #3复制
1
说明/提示
数据规模与约定
对于 100% 的数据,有 1≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1×109,酸度和苦度不同时为 1 和 0。
#include<bits/stdc++.h>
using namespace std;
int min1=2147483647 ;//定义最小值为int的极限
int s[11],b[11];
int n;
void dfs(int i,int a,int d)
{
if(i>n){//当编号大于n时,则可以终止搜索
if(a==1&&d==0){//排除所有配料都未选的情况
return;
}
if(abs(a-d)<min1){//比较出最小值
min1=abs(a-d);
}
return;
}
dfs(i+1,a*s[i],d+b[i]);//选择编号为i,则酸度苦读按公式增加,进入下一次搜索
dfs(i+1,a,d);//没有选择编号为i的配料,则酸度与苦度不增加,进入下一次搜索
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&s[i],&b[i]);//输入第i中配料时的酸度与苦度
}
dfs(1,1,0);
printf("%d",min1);
return 0;
}
该题是一个经典的搜索树问题。我们通过深搜,进行各编号选与不选的选择,从而实现该题的各种情况。再将各种情况的绝对差进行比较从而得出最小值。但是,要注意将一种配料未选的情况排除。
P1443 马的遍历
题目描述
有一个 n×m 的棋盘,在某个点 (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n,m,x,y。
输出格式
一个 n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 −1−1)。
输入输出样例
输入 #1复制
3 3 1 1
输出 #1复制
0 3 2 3 -1 1 2 1 4
说明/提示
数据规模与约定
对于全部的测试点,保证 1≤x≤n≤400,1≤y≤m≤400。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[401][401];
struct point{//定义包含步数的坐标点的结构体
int x;
int y;
int step;
};
int dx[8]={1,2,2,1,-1,-2,-2,-1};
int dy[8]={2,1,-1,-2,-2,-1,1,2};//表示马在棋盘中的各行走方向
int main()
{
int n,m;
int p,q;
scanf("%d %d %d %d",&n,&m,&p,&q);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int flag=0;//指示标
queue<point> r;//定义队列
struct point start;//表示起点坐标以及步数
start.x=q;
start.y=p;
start.step=0;
r.push(start);//将起点的结构体压入队列中
int v[401][401]={0};//初始化指示数组为0
int min1=99999;//定义一个很大的值,方便求最下值
while(!r.empty()){//判断队列是否为空队列,是则停止搜索
int x1=r.front().x;//提取首队列坐标及步数
int y1=r.front().y;
int step1=r.front().step;
if(x1==j&&y1==i){//如果抵达终点
flag=1;//指示标赋值为1
if(step1<min1){
min1=step1;//求最小
}
break;//终点后终止循环
}
for(int i=0;i<8;i++){
int tx,ty;
tx=x1+dx[i];
ty=y1+dy[i];
if(tx>=1&&tx<=m&&ty>=1&&ty<=n&&v[tx][ty]==0){//如果下一点未出界且未访问,则执行将下一点坐标压入队列的操作
struct point temp;
temp.x=tx;
temp.y=ty;
temp.step=step1+1;
r.push(temp);
v[tx][ty]=1;//设置为已访问状态
}
}
r.pop();//将首队列挤出
}
if(flag==1){//指示标起判断能否到达的作用
a[i][j]=min1;。。将最小值带入各矩阵点
}else{
a[i][j]=-1;
}
}
}
for(int i=1;i<=n;i++){//输出最小步数举证
for(int j=1;j<=m;j++){
printf("%d\t",a[i][j]);
}
printf("\n");
}
return 0;
}
该题可用dfs以及bfs的解法。此代码是典型的bfs广搜,注意一下马在棋盘中的行走方式即可。