学习内容
1.背英语四级词汇:2小时7:50~8:50,4:00~5:00
2.刷题,并在刷题过程中强化对深度优先搜索概念的理解和引用。
3.听学长讲解深度优先搜索和广度优先搜索以及快排相关知识点。
刷题
1.
P2392 kkksc03考前临时抱佛脚
题目背景
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
#include<stdio.h>
const int N=100000,M=100000;
int n[4],a[N],f[M];
int res;//所有科目总耗时
int main()
{
for (int i=1;i<=4;i++)//分别输入每门课有多少道题
scanf("%d",&n[i]);
for (int i=1;i<=4;i++)
{
int sum=0;//将结果清零以便下门科目耗时能顺利计算
for (int j=1;j<=n[i];j++)
{
scanf("%d",&a[j]);//为每个提姆所耗时赋值
sum+=a[j];//计算总耗时
}
for(int i=0;i<M;i++)//将结果清零以便下门科目耗时能顺利计算
{
f[i]=0;
}
for (int j=1;j<=n[i];j++)
for (int k=sum/2;k>=a[j];k--)//在不超过总耗时一半的情况下,总耗时减去最大耗时组合的耗时,就是这门课的最少耗时
if(f[k]>=f[k-a[j]]+a[j])
f[k]=f[k];
else
f[k]=f[k-a[j]]+a[j];
res+=sum-f[sum/2];//存入总耗时
}
printf("%d\n",res);
return 0;
}
题解:总耗时为4个科目的单科耗时相加,对于一个科目,首先计算出所有题目的时间之和,之后,找到总耗时最大且不超过时间之和的一半的组合,将时间之和减去组合耗时所得的结果,即为这个科目的耗时,其他科目重复上述过程即可。
2.八皇后
P1219 [USACO1.5]八皇后 Checker Challenge
题目描述
一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。
上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:
行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6
列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5
这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。
输入格式
一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。
输出格式
前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。
输入输出样例
输入 #1复制
6
输出 #1复制
2 4 6 1 3 5 3 6 2 5 1 4 4 1 5 2 6 3 4
#include<stdio.h>
const int Max=14; //数据范围在6到13之间
int n,sum; //输入的n的值,和所有的解法
int a[14]; //存放皇后所在的列数
int book[3][14*2]; //book[0][i]=1表示第i列已被放置皇后,book[1][i]=1表示行列和为i的对角线已存在皇后(右上到左下),book[2][i]=2表示行列之差加上n的值为i的对角线已存在皇后(左上到右下)
void dfs(int i);
int main()
{
scanf("%d",&n);
dfs(1);
printf("%d\n",sum);
return 0;
}
void dfs(int i)
{
for(int j=1;j<=n;j++)
{
if(!a[i]&&!book[0][j]&&!book[1][i+j]&&!book[2][i-j+n]) //使得每行、每列有且只有一个,每条对角线上最多有一个棋子
{
a[i]=j; //存储皇后的列
book[0][j]=1;
book[1][i+j]=1;//对于从右上到左下的对角线,他们的行列之和相等
book[2][i-j+n]=1;//对于从左上到右下的对角线,他们的行列之差相等,为避免出现负数,这里加上总数n
dfs(i+1); //
a[i]=0; //重置数据
book[0][j]=0;
book[1][i+j]=0;
book[2][i-j+n]=0;
}
}
if(i>n)
{
if(sum>2)//三个之后的解省略
{
sum++;
return;
}
else//三个之前的解输出
{
sum++;
for(int i=1;i<=n;i++)
{
if(i==1)
printf("%d",a[i]);
else
printf(" %d",a[i]);//输出“ ”以符合题目要求
}
printf("\n");
return;
}
}
}
题解:遍历顺序为从左往右,到一行最后一个值时从下一行第一个按照上述顺序继续,在“摆出”可行的位置后按照题目要求判断是否符合题意(每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子),符合提议的就算作一个解,,先输出前三个解,最后输出解的总数。
3.
P1135 奇怪的电梯
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第ii层楼(1 \le i \le N)(1≤i≤N)上有一个数字K_i(0 \le K_i \le N)Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如:3, 3 ,1 ,2 ,53,3,1,2,5代表了K_i(K_1=3,K_2=3,…)Ki(K1=3,K2=3,…),从11楼开始。在11楼,按“上”可以到44楼,按“下”是不起作用的,因为没有-2−2楼。那么,从AA楼到BB楼至少要按几次按钮呢?
输入格式
共二行。
第一行为33个用空格隔开的正整数,表示N,A,B(1≤N≤200, 1≤A,B≤N)N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为NN个用空格隔开的非负整数,表示K_iKi。
输出格式
一行,即最少按键次数,若无法到达,则输出-1−1。
输入输出样例
输入 #1复制
5 1 5 3 3 1 2 5
输出 #1复制
3
#include<stdio.h>
int m[10000]={0},n[10000]={0};
int N,a,b,x=1;
void dfs(int x);
int main()
{
scanf("%d%d%d",&N,&a,&b);
for(int i=1;i<=N;i++)
scanf("%d",&n[i]);
m[a]=1;//将a层电梯初值设为1
dfs(1);
printf("%d",m[b]-1);
return 0;
}
void dfs(int x)
{
while(x)//至少循环一次
{
x=0;
for(int i=1;i<=N;i++)
{
if(m[i]>0)//每次从a层开始
{
if(i-n[i]>0)//能下降
{
if(m[i-n[i]]==0||m[i-n[i]]>m[i]+1)
{
m[i-n[i]]=m[i]+1;//下降后次数=下降前次数+1
x=1;//满足条件继续循环
}
}
if(i+n[i]<=N)//不超过最大楼层
{
if(m[i+n[i]]==0||m[i+n[i]]>m[i]+1)
{
m[i+n[i]]=m[i]+1;//上升后次数=上升前次数+1
x=1;//满足条件继续循环
}
}
}
}
}
}
题解:首先满足dfs的要求是当前楼层数能下降且上升后不超过最大楼层数,且不论是上升还是下降算作一次操作,在循环结束后输出总操作次数