迷宫
题目描述
给定一个 N \times MN×M 方格的迷宫,迷宫里有 TT 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
输入格式
第一行为三个正整数 N,M,TN,M,T,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 SX,SY,FX,FYSX,SY,FX,FY,SX,SYSX,SY 代表起点坐标,FX,FYFX,FY 代表终点坐标。
接下来 TT 行,每行两个正整数,表示障碍点的坐标。
输出格式
输出从起点坐标到终点坐标的方案总数。
输入输出样例
输入 #1复制
2 2 1 1 1 2 2 1 2输出 #1复制
1说明/提示
对于 100\%100% 的数据,1 \le N,M \le 51≤N,M≤5,1 \le T \le 101≤T≤10,1 \le SX,FX \le n1≤SX,FX≤n,1 \le SY,FY \le m1≤SY,FY≤m。
思路: 找迷宫的通关次数据比较小的时候,我们可以采用dfs(深度搜索)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int N,M,T,p,q,sum=0;
int book[6][6]={0},a[6][6]={0};
int dfs(int x,int y,int step)
{
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//走四个方向数组
int tx,ty,k;
if(x==p&&y==q)//到达终点的时候次数加1
{
sum++;
return 0;//返回最近的dfs函数
}
for(k=0;k<4;k++)//四种走法的遍历
{
tx=x+next[k][0];
ty=y+next[k][1];
if(tx<1||ty<1||tx>N||ty>M)//判断是否越界
continue;//此种走法越界了就另一种走法
if(a[tx][ty]==0&&book[tx][ty]==0)//该位置不是障碍且没有走过的时候
{
book[tx][ty]=1;//标记这个点来过
dfs(tx,ty,step+1);//调用dfs走下一步
book[tx][ty]=0;//回溯
}
}
return sum;
}
int main()
{
int sx,sy,t1,t2,ans=0;
scanf("%d%d%d",&N,&M,&T);//N行M列T个障碍
scanf("%d%d%d%d",&sx,&sy,&p,&q);//起点坐标和终点坐标的
for(int i=0;i<T;i++)
{
scanf("%d%d",&t1,&t2);
a[t1][t2]=1;//障碍为1
}
book[sx][sy]=1;//设置初始点来过
ans=dfs(sx,sy,0);
printf("%d",ans);
return 0;
}
/*
0 1
0 0
*/
自然数的拆分问题
题目描述
任何一个大于 11 的自然数 nn,总可以拆分成若干个小于 nn 的自然数之和。现在给你一个自然数 nn,要求你求出 nn 的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。
输入格式
输入:待拆分的自然数 nn。
输出格式
输出:若干数的加法式子。
输入输出样例
输入 #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说明/提示
数据保证,1\le n\le 81≤n≤8。
思路:我们观察最后面几项总是前一个序列最后的数俩俩相加 ,因此我们采用dfs回溯出多种方案。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int n,a[9];
void print(int cnt)//(用于输出的函数)
{
for(int i=0;i<cnt-1;i++)
{
printf("%d",a[i]);
printf("+");
}
printf("%d",a[cnt-1]);
puts("");
}
void dfs(int x,int sum,int cnt)//x为该数和的元素,sum为当前的的和,cnt用于数组存入数据的下标
{
if(x==n)return ;//当x达到输入的数的时候不需要输出直接回到最近的dfs函数处
if(sum==n)//总和达到输入的数字的时候
{
print(cnt);//调用输出函数输出存入a数组的数
return ;
}
for(int i=x;i<=n-sum;i++)//此处需要注意的是i=x开始遍历而不是i=1(i=1会导致输出重复)(例如1 1 1 2 1和1 1 1 1 2)是一种情况
{
a[cnt]=i;//存入数组a
dfs(i,sum+i,cnt+1);//调用dfs函数深度搜索直到总和达到输入的数字再逐步返回输出其他情况
}
}
int main()
{
scanf("%d",&n);
dfs(1,0,0);
}
PERKET
题目描述
Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 nn 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 ss 和苦度 bb。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 nn,表示可供选用的食材种类数。
接下来 nn 行,每行 22 个整数 s_isi 和 b_ibi,表示第 ii 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例
输入 #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\%100% 的数据,有 1 \leq n \leq 101≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1 \times 10^91×109,酸度和苦度不同时为 11 和 00。
说明
- 本题满分 7070 分。
- 题目译自 COCI2008-2009 CONTEST #2 PERKET,译者 @mnesia。
附件下载
contest2_tasks.pdf101.88KB
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> struct food { int s;//酸度 int k;//苦度 }a[11]; int n,min=1000000001,book[11]={0};//book数组用于记录是否加过该种调料 void dfs(int x,int y,int step)//step用于计录加了多少种调料 { if(step==n+1)return ;//此时所有调料都加了一遍则返回 for(int i=1;i<=n;i++)//从第一种调料开始 { if(book[i]==0)//没有加过的调料 { book[i]=1;//设置为加过 x*=a[i].s;//计算总酸度 y+=a[i].k;//计算总苦度 if(abs(x-y)<min)//酸度和苦度的差值若小于min则更新min的值 { min=abs(x-y); } dfs(x,y,step+1); book[i]=0;//撤回这种调料 x/=a[i].s; y-=a[i].k; } } return ; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d %d",&a[i].s,&a[i].k); } dfs(1,0,0);//此处的调用需要1 0 0,而不是0 0 0 (因为酸度是相乘) printf("%d",min); }