1.14今日总结

题目背景

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的问题。总体来说收获不错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值