题目背景
kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。
题目描述
这次期末考试,kkksc03 需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s_1,s_2,s_3,s_4s1,s2,s3,s4 道题目,完成每道题目需要一些时间,可能不等(A_1,A_2,\ldots,A_{s_1}A1,A2,…,As1,B_1,B_2,\ldots,B_{s_2}B1,B2,…,Bs2,C_1,C_2,\ldots,C_{s_3}C1,C2,…,Cs3,D_1,D_2,\ldots,D_{s_4}D1,D2,…,Ds4)。
kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。
由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。
输入格式
本题包含 55 行数据:第 11 行,为四个正整数 s_1,s_2,s_3,s_4s1,s2,s3,s4。
第 22 行,为 A_1,A_2,\ldots,A_{s_1}A1,A2,…,As1 共 s_1s1 个数,表示第一科习题集每道题目所消耗的时间。
第 33 行,为 B_1,B_2,\ldots,B_{s_2}B1,B2,…,Bs2 共 s_2s2 个数。
第 44 行,为 C_1,C_2,\ldots,C_{s_3}C1,C2,…,Cs3 共 s_3s3 个数。
第 55 行,为 D_1,D_2,\ldots,D_{s_4}D1,D2,…,Ds4 共 s_4s4 个数,意思均同上。
输出格式
输出一行,为复习完毕最短时间。
输入输出样例
输入 #1复制
1 2 1 3 5 4 3 6 2 4 3
输出 #1复制
20
说明/提示
1\leq s_1,s_2,s_3,s_4\leq 201≤s1,s2,s3,s4≤20。
1\leq A_1,A_2,\ldots,A_{s_1},B_1,B_2,\ldots,B_{s_2},C_1,C_2,\ldots,C_{s_3},D_1,D_2,\ldots,D_{s_4}\leq601≤A1,A2,…,As1,B1,B2,…,Bs2,C1,C2,…,Cs3,D1,D2,…,Ds4≤60
这个题可以用背包解决 ,但是背包问题有些遗忘,所以我采取了dfs解法。
首先说说解题思路:左右脑计算,将时间分为两边,最后左右脑大的值为所需,然后在所有选择中最大值中找出最小值为最佳解。最后把这些最佳解加上就为该题答案。
代码实现:
#include<stdio.h>
int a[5][21];
int s[5];
int left,right;//左脑和右脑
int max; //最大值
int min=10000000;//最小
int sum;//总和
void dfs(int x,int y)//y表示第几个作业,x表示y个作业中的第x个数据
{
if(x>s[y])//表示x不在y作业范围内
{
if(right>=left)//求最大值,因为两边可以同时进行,所以需去最大值
max=right;
else
max=left;
if(min>max)//在所有的最大值中去最小值,即最佳答案
{
min=max;
}
return ;
}
else
{
left+=a[x][y];//左脑选择
dfs(x+1,y);
left-=a[x][y];//回溯
right+=a[x][y];//右脑选择
dfs(x+1,y);
right-=a[x][y];//回溯
}
}
int main()
{
for(int i=1;i<=4;i++)
scanf("%d",&s[i]);//输出4个科目各有多少题
for(int i=1;i<=4;i++)
{
for(int j=1;j<=s[i];j++)
scanf("%d",&a[j][i]);//表示第i科第j题所耗费的时间
dfs(1,i);
sum+=min;//重置
min=10000000;
left=0;
right=0;
}
printf("%d",sum);
}
题目描述
有一个 n \times mn×m 的棋盘,在某个点 (x, y)(x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n, m, x, yn,m,x,y。
输出格式
一个 n \times mn×m 的矩阵,代表马到达某个点最少要走几步(左对齐,宽 55 格,不能到达则输出 -1−1)。
输入输出样例
输入 #1复制
3 3 1 1
输出 #1复制
0 3 2 3 -1 1 2 1 4
说明/提示
数据规模与约定
对于全部的测试点,保证 1 \leq x \leq n \leq 4001≤x≤n≤400,1 \leq y \leq m \leq 4001≤y≤m≤400
刚刚看这道题的时候,我以为他给的数据出错了,后面再次思考时,就知道这“马”是象棋里的马。
马飞日。。。。
这题是运用bfs。
代码实现:
#include<stdio.h>
struct node{
int a;//表示行
int b;//表示列
};
int next[8][2]={{2,1},{2,-1},{1,2},{1,-2},{-2,1},{-2,-1},{-1,2},{-1,-2}};//马向八个方向移动
int a1[10000000];//行的队列,开大一点
int b1[10000000];//列的队列
int front;//队首
int back;//队尾
int flag[401][401];//标记
int map[401][401];//记录步数
void push(int A,int B)//输入
{
a1[back]=A;
b1[back]=B;
back++; //队尾
}
int empty()//判断是否为空
{
int d=0;
if(front==back)
d=1;
return d;
}
void pop()//弹出队首的数据
{
a1[front]=a1[front+1];
b1[front]=b1[front+1];
front++;
}
int main()
{
int n,m,x,y;
scanf("%d%d%d%d",&n,&m,&x,&y);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
map[i][j]=-1;//全部标记为-1
}
struct node u;
map[x][y]=0;//将起点标记为0
flag[x][y]=1;//标记为已走过
push(x,y);//把原位置放入队列
while(empty()==0)//非空
{
u.a=a1[front];//取队首数据
u.b=b1[front];//取队首数据,表示从队首开始遍历
pop();//弹出队首
for(int i=0;i<8;i++)//八个方向
{
int xx=u.a+next[i][0];//移动
int yy=u.b+next[i][1];//移动
if(xx<1||xx>n||yy<1||yy>m||flag[xx][yy]==1)//所移动的位置应该不超出边界同时且没有被标记
continue;
flag[xx][yy]=1;//标记
push(xx,yy);//把现在的位置放入队列
map[xx][yy]=map[u.a][u.b]+1;//步数加一
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
printf("%-5d",map[i][j]);//输出
printf("\n");
}
}
今日总结:写了两道关于dfs和bfs的问题。总体来说收获不错。