1、Xxy 的车厢调度
(train.cpp/c/pas)
Description
,
再从 B 方向驶出,同时它的车厢可以重新组合。假设
从 A 方向驶来的火车有 n 节(n<=1000) ,分别按照顺
序编号为 1,2,3,…,n。假定在进入车站前,每节
车厢之间都不是连着的,并且它们可以自行移动到 B
处的铁轨上。 另外假定车站 C 可以停放任意多节车厢。
但是一旦进入车站 C,它就不能再回到 A 方向的铁轨
上了,并且一旦当它进入 B 方向的铁轨,它就不能再
回到车站 C。
负责车厢调度的 xxy 需要知道能否使它以
a1,a2,…,an 的顺序从 B 方向驶出,请来判断能否得到
指定的车厢顺序。
Input
输入文件的第一行为一个整数 n,其中 n<=1000,表示有 n 节车厢,第二行为 n 个数字,表
示指定的车厢顺序。
Output
如果可以得到指定的车厢顺序,则输出一个字符串”YES”,否则输出”NO”(注意要大写,不
包含引号) 。还有,xxy 说了 这题 AC 有糖吃。
Example
train.in train.out
5
5 4 3 2 1
YES
Hint
对于 50%的数据,1<=N<=20。
对于 100%的数据,1<=N<=1000。
【思路】
模拟法做 B相当于是一个栈
如果站内没有当前行驶来的车,则将小于当前车的编号的车全部入栈(包括当前车)
再将这辆车驶出;若当前车在栈中直接将它驶出。否则无解。
(注意输出大小写。。。吃亏了。。。)
【代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 using namespace std; 5 const int maxx=1001; 6 int a[maxx]; 7 int stack[maxx]; 8 int main() 9 { 10 // freopen("train.in","r",stdin); 11 // freopen("train.out","w",stdout); 12 int n; 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) 15 scanf("%d",&a[i]); 16 int cur=1; 17 int top=0; 18 for(int i=1;i<=n;i++) 19 { 20 while(cur<=a[i]) 21 stack[++top]=cur++; 22 if(stack[top]==a[i]) 23 --top; 24 else 25 { 26 printf("NO"); 27 return 0; 28 } 29 30 } 31 printf("YES"); 32 // fclose(sdtin); 33 // fclose(stdout); 34 return 0; 35 }
2、迷 宫
(maze.cpp/c/pas)
Description
Karles 和朋友到迷宫玩耍,没想到遇上了 10000000 年一次的大洪水,好在 Karles 是一个喜
欢思考的人,他发现迷宫的地形和洪水有如下性质:
①迷宫可以被看做是一个 N*M 的矩形方阵,其中左上角坐标为(1,1),右下角坐标为(n,m),
每个格子(i,j)都有一个高度 h(i,j)。
②洪水从(sx,sy)开始,如果一个格子被洪水淹没,那这个格子四周比它低(或相同)的格子
也会被淹没。
现在 Karles 想请你帮忙算算,有多少个格子不会被淹没,以及 Karles 想问一下格子(x,y)是否
被淹没,如果被淹没的话就输出”Yes”,否则输出”No”。
Input
第一行包含两个整数 n,m。
以下 n 行,每行 m 个数,第 i 行第 j 个数表示格子高度 h(i,j)。
下面一行包含两个整数 sx,sy,表示最初被洪水淹没的格子。
下面一行包含一个整数 q,表示询问的数量。
最后 q 行每行包含两个整数 x,y,表示询问的格子。
Output
输出的第一行,为永远不会被淹没的格子的数量。
以下 q 行,为格子被淹没的情况,输出”Yes”或者”No”(不包含引号)
Example
maze.in maze.out
3 3
1 2 3
2 3 4
3 4 5
2 2
2
1 2
2 3
5
Yes
No
Hint
对于 10%的数据,(sx,sy)为迷宫内的最高点。
对于 30%的数据,1<=N,M<=5,q=1。
对于 60%的数据,1<=N,M<=100,q<=100。
对于 100%的数据,1<=N,M<=2000,q<=1000。
【思路】广搜 相当于细胞搜索;
从被洪水淹没的格子开始搜素(方向为上下左右),如果海拔小于等于当前格子则入队,并做好标记表示已经被淹了,
入队的条件为 没有出界,海拔小于等于当前搜索的海拔 并且没有被淹(即还没有做标记)!!!(经常忘记)
直到队列元素为空 ,全部都扫一遍,没有打标记的就是没有淹的;
(还是要注意输出大小写。。。)
【代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 using namespace std; 5 const int maxx=2001; 6 int mmap[maxx][maxx]; 7 int dx[4]={0,1,-1,0}, 8 dy[4]={1,0,0,-1}; 9 bool vis[maxx][maxx]; 10 int qque[maxx][maxx]; 11 int n,m; 12 void bfs(int x,int y) 13 { 14 vis[x][y]=1; 15 int head=0,t=1; 16 qque[1][1]=x; 17 qque[1][2]=y; 18 do 19 { 20 head++; 21 for(int i=0;i<=3;i++) 22 { 23 int xx=qque[head][1]+dx[i]; 24 int yy=qque[head][2]+dy[i]; 25 if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&mmap[xx][yy]<=mmap[qque[head][1]][qque[head][2]]&&!vis[xx][yy]) 26 { 27 vis[xx][yy]=1; 28 t++; 29 qque[t][1]=xx; 30 qque[t][2]=yy; 31 } 32 } 33 }while(head<=t); 34 } 35 int main() 36 { 37 //freopen("maze.in","r",stdin); 38 //freopen("maze.out","w",stdout); 39 scanf("%d%d",&n,&m); 40 for(int i=1;i<=n;i++) 41 for(int j=1;j<=m;j++) 42 scanf("%d",&mmap[i][j]); 43 int x,y; 44 scanf("%d%d",&x,&y); 45 bfs(x,y); 46 int sum=0; 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=m;j++) 49 { 50 if(!vis[i][j]) 51 sum++; 52 } 53 printf("%d ",sum); 54 int t; 55 scanf("%d",&t); 56 int i,j; 57 while(t--) 58 { 59 scanf("%d%d",&i,&j); 60 if(vis[i][j]) 61 printf("No "); 62 else 63 printf("Yes "); 64 } 65 // fclose(stdin); 66 // fclose(stdout); 67 return 0; 68 }
3.发 零 食
(dropping.cpp/c/pas)
Description
HKD 看学弟学妹们学习辛苦,决定给发零食吃
HKD 是土豪,所以他决定买零食的时候,从 1 块钱的开始买,然后买 2 块钱的,然后 3 块钱
的,……,直至 D 块钱的。而且 k 块钱的零食买 2^(k-1)个。
但 HKD 从来不吃零食,所以他不知道他买的零食是否好吃。
于是他把所有零食编号,怎么编呢?
对于价钱为 k 的零食,从 1 开始编,然后 2,3,编到 2^(k-1)
例:1 块钱的:1
2 块钱的:1 2
3 块钱的:1 2 3 4
学编程的基本功是搜索嘛
为了考验学弟学妹们的搜索能力
HKD 把所有零食掺杂在了一起,送到学弟学妹们的面前(送货上门,真好)
他规定:
1、只能排队一个一个开始搜
2、所有人最终只能吃 1 个零食
3、所有人只能吃最贵的零食
4、 所有人搜索零食的时候, 只能从 1 块钱的开始搜, 然后搜 2 块钱的, 然后搜 3 块钱的……,
直到最贵的
5、初始时认为所有零食都是好吃的
6、 为了增加难度, HKD 制定了新规定: 若一个人搜到的第 i 块钱的编号为 j 的零食是好吃的,
那么他就把这个零食更改为不好吃,然后去搜第 i+1 块钱的编号为 j*2-1 的零食。若一个人
搜到的第 i 块钱的编号为 j 的零食是不好吃的,那么他就把这个零食更改为好吃,然后去搜
第 i+1 块钱的编号为 j*2 的零食
注:若 n 个人都最后搜到了同一个零食,那么他们就分享一个吧
然而不知道为啥,HKD 想知道最后一个人吃的是编号为几的零食
那就麻烦最后一个人告诉他吧
注:若其中有一个人无法搜到最贵的零食,就告诉他-1
Input
第一行输入测试点编号
下一行输入 T,表示有 T 组数据
接下来 T 行,每行输入 2 个数输入 D 和学弟学妹的人数 M
Output
对于每组测试数据
输出一行 k : ans,表示第 k 组数据的答案为 ans
冒号与每个数字之间空 1 格
每 2 组数据之间空一行
Example
dropping.in dropping.out
1
6
4 2
3 4
10 1
2 2
8 128
1 : 12
2 : 7
3 : 512
4 : 3
5 : 255
Hint
测试点编号
T D
1、2
<=1 <=10
3、4、5
<=20 <=25
6、7、8、9
<=700 <=30
10 <=1 <=1
学弟学妹人数 M <2^31 且不超过 D 块钱的零食个数。
【思路】:由题目描述可知,这是一棵完全二叉树;
每一层为 2的层次方-1;从第一层的第一个结点开始,到每一个结点的条件是好吃与不好吃;
最后一定会出界,出界时跳出;将刚出界点的编号/2,就是出界之前的点;即为最贵的零食;
:结点k的左右子结点的标号为2*看,2*k+1;
之前没想到是因为不理解题意;而且没有敏感的认识到2^k-1为完全二叉树每层的结点数
状态改变 循环+取反 边界:为出界即超过最贵的零食的那一层;
学到的 1<<Max 为2^max‘
【代码】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxx=20; 6 int s[1<<maxx];//为2的maxx次方,因为最大结点数为2的maxx-1; 7 int main() 8 { 9 int n,k=1; 10 scanf("%d",&n);//测试点 11 int t; 12 scanf("%d",&t);//t组测试数据 13 while(t--) 14 { 15 int d,I;//钱和同学 16 scanf("%d%d",&d,&I); 17 int n=(1<<d)-1;//n为最大结点的标号 18 memset(s,0,sizeof(s));//好吃与不好吃 19 for(int i=0;i<I;i++)//从第一个同学开始搜 20 { 21 k=1;//从1块钱开始搜 22 for(;;) 23 { 24 s[k]=!s[k];//状态变成相反 25 k=s[k]?k*2:k*2+1;//去哪个零食 26 if(k>n)break;//已经出界了跳出 27 } 28 } 29 printf("%d ",k/2);//出界之后/2就是这个结点的爸爸 30 } 31 return 0; 32 }