3月13日8:30 ~12:00 初一搜索测试总结
先总结
这次测试暴露出来很多问题,如:太懒了…(以下省略一堆)
何为懒惰,即打bfs太难了,就去打dfs,然后…就TLE了
再总结
题有点多,时间不够,挑几道经典的(继续懒惰)
1.碎纸机
作者的话
这题可以简简单单的打代码,但…头一天没睡好(失眠了),就…打得及其复杂
题目描述
你现在负责设计一种新式的碎纸机。一般的碎纸机会把纸切成小片,变得难以阅读。而你设计的新式的碎纸机有以下的特点:
每次切割之前,先要给定碎纸机一个目标数,而且在每张被送入碎纸机的纸片上也需要包含一个数。
碎纸机切出的每个纸片上都包括一个数。
要求切出的每个纸片上的数的和要不大于目标数而且与目标数最接近。
举一个例子,如下图,假设目标数是50,输入纸片上的数是12346。碎纸机会把纸片切成4块,分别包含1,2,34和6。这样这些数的和是43 (= 1 + 2 + 34 + 6),这是所有的分割方式中,不超过50,而又最接近50的分割方式。又比如,分割成1,23,4和6是不正确的,因为这样的总和是34 (= 1 + 23 + 4 + 6),比刚才得到的结果43小。分割成12,34和6也是不正确的,因为这时的总和是52 (= 12 + 34 + 6),超过了50。
还有三个特别的规则:
如果目标数和输入纸片上的数相同,那么纸片不进行切割。
如果不论怎样切割,分割得到的纸片上数的和都大于目标数,那么打印机显示错误信息。
如果有多种不同的切割方式可以得到相同的最优结果。那么打印机显示拒绝服务信息。比如,如果目标数是15,输入纸片上的数是111,那么有两种不同的方式可以得到最优解,分别是切割成1和11或者切割成11和1,在这种情况下,打印机会显示拒绝服务信息。
为了设计这样的一个碎纸机,你需要先写一个简单的程序模拟这个打印机的工作。给定两个数,第一个是目标数,第二个是输入纸片上的数,你需要给出碎纸机对纸片的分割方式。
有点多
输入格式
输入包括多组数据,每一组包括一行。
每行上包括两个正整数,分别表示目标数和输入纸片上的数。
已知输入保证:两个数都不会以0开头,而且两个数至多都只包含6个数字。
输入的最后一行包括两个0,这行表示输入的结束。
输出格式
样例输入
50 12346
376 144139
927438 927438
18 3312
9 3142
25 1299
111 33333
103 862150
6 1104
0 0
样例输出
43 1 2 34 6
283 144 139
927438 927438
18 3 3 12
error
21 1 2 9 9
rejected
103 86 2 15 0
rejected
思路
这题很像添加号问题(暂无链接),只需要小打一波深搜就欧克了,注意特别规则
代码
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int k,b,n;
int a[10];
int ansf[10],anst[10],Max,Maxj;
int d[1000005];
void dfs(int i,int j,int sum){
if(max(0,ansf[j])+sum>k) return;
if(i==n+1){
if(sum+max(0,ansf[j])>Max){
Maxj=j;
Max=sum+max(0,ansf[j]);
for(int l=1;l<=Maxj;++l){
anst[l]=ansf[l];
}
if(anst[Maxj]==-1) --Maxj;
}
++d[sum+max(0,ansf[j])];
return;
}
if(ansf[j]!=-1){
dfs(i,j+1,sum+ansf[j]);
ansf[j]=ansf[j]*10+a[i];
dfs(i+1,j,sum);
ansf[j]/=10;
}else{
ansf[j]=a[i];
dfs(i+1,j,sum);
ansf[j]=-1;
}
return;
}
int main() {
// freopen("paper.in","r",stdin);
// freopen("paper.out","w",stdout);
while(1){
memset(d,0,sizeof(d));
memset(ansf,-1,sizeof(ansf));
Max=0;
scanf("%d%d",&k,&b);
if(k==0&&b==0) return 0;
if(k==b) {
printf("%d %d\n",k,b);
continue;
}
n=0;
while(b!=0){
a[++n]=b%10;
b/=10;
}
reverse(a+1,a+n+1);
int tot=0;
for(int i=1;i<=n;++i){
tot+=a[i];
}
if(tot>k){
printf("error\n");
continue;
}
dfs(1,1,0);
if(d[Max]>1) printf("rejected\n");
else{
printf("%d ",Max);
for(int i=1;i<=Maxj;++i){
printf("%d ",anst[i]);
}
putchar('\n');
}
}
return 0;
}
2.A计划
作者的话
这就是传说中的表现出懒惰之处的题
题目描述
可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。
现据密探所报,公主被关在一个两层的迷宫里,迷宫的入口是
S(0,0,0),公主的位置用P表示,时空传输机用 # 表示,墙用 * 表示,平地用 . 表示。骑士们一进入时空传输机就会被转到另一层的相对位置,但如果被转到的位置是墙的话,那骑士们就会被撞死。骑士们在一层中只能前后左右移动,每移动一格花1时刻。层间的移动只能通过时空传输机,且不需要任何时间。
输入格式
输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小。T如上所意。接下去的前 N ⋅ M N\cdot M N⋅M表示迷宫的第一层的布置情况,后 N ⋅ M N\cdot M N⋅M表示迷宫第二层的布置情况。
输出格式
如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。
样例输入
1
5 5 14
S*#*.
.#...
.....
****.
...#.
..*.P
#.*..
***..
...*.
*.#..
样例输出
YES
数据范围与提示
1 ≤ N , M ≤ 10 1 \le N,M \le10 1≤N,M≤10
思路
这题就是简单的三维迷宫,注意走到#就得飞,所以避免炸掉…
代码
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n,m,h;
int ex,ey,ez;
char a[3][15][15];
int dirx[8]={1,-1},
diry[8]={0,0,1,-1};
int book[3][15][15];
void bfs(int k,int i,int j){
queue<int> qx;
queue<int> qy;
queue<int> qz;
qx.push(i);
qy.push(j);
qz.push(k);
while(qx.size()>0){
int x=qx.front(),y=qy.front(),z=qz.front();
qx.pop();
qy.pop();
qz.pop();
if(a[z][x][y]=='P') return;
if(a[z][x][y]=='#'){
if(z==1&&a[2][x][y]!='*'&&
a[2][x][y]!='#'&&book[2][x][y]>book[1][x][y]) {
book[2][x][y]=book[1][x][y];
qx.push(x);
qy.push(y);
qz.push(2);
}
else if(z==2&&a[1][x][y]!='*'&&
a[1][x][y]!='#'&&book[1][x][y]>book[2][x][y]) {
book[1][x][y]=book[2][x][y];
qx.push(x);
qy.push(y);
qz.push(1);
}
}else{
for(int K=0;K<4;++K){
int dx=x+dirx[K],dy=y+diry[K];
if(dx>0&&dx<=n&&dy>0&&dy<=m&&
book[z][dx][dy]>book[z][x][y]+1&&a[z][dx][dy]!='*'){
book[z][dx][dy]=book[z][x][y]+1;
qx.push(dx);
qy.push(dy);
qz.push(z);
}
}
}
}
return;
}
int main() {
// freopen("plan.in","r",stdin);
// freopen("plan.out","w",stdout);
int t;
int C;
scanf("%d",&C);
while(C--){
memset(book,0x7f,sizeof(book));
scanf("%d %d %d",&n,&m,&t);
int x,y,z;
for(int i=1;i<=n;++i){
scanf("\n");
for(int j=1;j<=m;++j){
scanf("%c",&a[1][i][j]);
if(a[1][i][j]=='S'){
z=1;
x=i;
y=j;
}
if(a[1][i][j]=='P'){
ez=1;
ex=i;
ey=j;
}
}
}
scanf("\n");
for(int i=1;i<=n;++i){
scanf("\n");
for(int j=1;j<=m;++j){
scanf("%c",&a[2][i][j]);
if(a[2][i][j]=='S'){
z=2;
x=i;
y=j;
}
if(a[2][i][j]=='P'){
ez=2;
ex=i;
ey=j;
}
}
}
book[z][x][y]=0;
bfs(z,x,y);
if(book[ez][ex][ey]<=t) printf("YES\n");
else cout << "NO" << endl;
}
return 0;
}
又总结
难的题就这样了,要勤奋,多打bfs对身体好