暑期集训1DAY
第一题是A - FatMouse and Cheese,其实就是一个滑雪的类似题目,只能往奶酪多的地方走,但是可以跳跃的走,在上下左右k步范围内的都行,主要的想法就是DFS搜索,每一次的四个方向DFS搜索,找到它其中的最大值,然后记录下来,和当前点的值加起来,就是当前点最终能吃到的最多奶酪.
jud[i][j]=max(i=0~k,j=0~4)+mapp[i][j]
这种回溯的题目都只能用DFS,如果用BFS会导致大量的多余运算,很有可能超时.我wa了多次,就是因为写成了BFS
Description
FatMouse begins by standing at location (0,0). He eats up the cheese where he stands and then runs either horizontally or vertically to another location. The problem is that there is a super Cat named Top Killer sitting near his hole, so each time he can run at most k locations to get into the hole before being caught by Top Killer. What is worse -- after eating up the cheese at one location, FatMouse gets fatter. So in order to gain enough energy for his next run, he has to run to a location which have more blocks of cheese than those that were at the current hole.
Given n, k, and the number of blocks of cheese at each grid location, compute the maximum amount of cheese FatMouse can eat before being unable to move.
Input
a line containing two integers between 1 and 100: n and k
n lines, each with n numbers: the first line contains the number of blocks of cheese at locations (0,0) (0,1) ... (0,n-1); the next line contains the number of blocks of cheese at locations (1,0), (1,1), ... (1,n-1), and so on.
The input ends with a pair of -1's.
Output
Sample Input
Sample Output
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<string> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 using namespace std; 9 int mapp[105][105]={0},n,jud[105][105]={0},k; 10 int dfs(int x,int y) 11 { 12 int i,max1=0; 13 if(!jud[x][y]) 14 { 15 for(i=1;i<=k;i++) 16 { 17 if(x+i<=n&&x+i>0&&mapp[x][y]<mapp[x+i][y]) 18 { 19 jud[x+i][y]=dfs(x+i,y); 20 if(jud[x+i][y]>max1) 21 max1=jud[x+i][y]; 22 } 23 if(x-i>0&&x-i<=n&&mapp[x][y]<mapp[x-i][y]) 24 { 25 jud[x-i][y]=dfs(x-i,y); 26 if(jud[x-i][y]>max1) 27 max1=jud[x-i][y]; 28 } 29 if(y+i<=n&&y+i>0&&mapp[x][y]<mapp[x][y+i]) 30 { 31 jud[x][y+i]=dfs(x,y+i); 32 if(jud[x][y+i]>max1) 33 max1=jud[x][y+i]; 34 } 35 if(y-i>0&&y-i<=n&&mapp[x][y]<mapp[x][y-i]) 36 { 37 jud[x][y-i]=dfs(x,y-i); 38 if(jud[x][y-i]>max1) 39 max1=jud[x][y-i]; 40 } 41 } 42 jud[x][y]=max1+mapp[x][y]; 43 } 44 return jud[x][y]; 45 } 46 int main() 47 { 48 int i,j; 49 while(scanf("%d%d",&n,&k)&&(n!=-1||k!=-1)) 50 { 51 memset(jud,0,sizeof(jud)); 52 for(i=1;i<=n;i++) 53 for(j=1;j<=n;j++) 54 scanf("%d",&mapp[i][j]); 55 printf("%d\n",dfs(1,1)); 56 } 57 return 0; 58 }
第二题是Escape,也是一个迷宫,规则是遇到转弯口就必定要转弯,不能往回走,不能停留,问能否找到出口。这题是一个BFS题目,用DFS也一样能解,毕竟路径只有有限的,这题是记忆化BFS,需要记录的是进入一个点是否有从同一个方向进入,如果有那这个点就不能走。然后走到每个点的时候需要判定一下是不是转弯口,如果是转弯口就一定要转弯.
关键在于来时方向的记录,和判定转弯,可以用dx[4],dy[4]来表示方向,然后px,py表示来时方向,如果前方有路可以走,判定一下两边是否有路可以走,可以走的话就只能走两边。后来发现用0,1,2,3就可以表示四个方向,方向记录也只需要一个参数,然后(dir[k]+1)%4或者(dir[k]+3)%4来向两边转弯.
wa了多次的原因是因为,走到出口的判定我判了遇到出口就出,其实是就算遇到出口,也需要判一下是不是直走的,如果是正前方是出口但能转弯也是不能出的.
Description
To shake off any people following you, you do not want to move in a straight line. In fact, you want to take a turn at every opportunity, never moving in any single direction longer than strictly necessary. This means that if, for example, you enter a tile from the south, you will turn either left or right, leaving to the west or the east. Only if both directions are blocked, will you move on straight ahead. You never turn around and go back!
Given a map of the room and your starting location, figure out how long it will take you to escape (that is: reach the edge of the room).
Input
a line with two integers separated by a space, h and w (1 <= h, w <= 80), the height and width of the room;
then h lines, each containing w characters, describing the room. Each character is one of . (period; an accessible space), # (a blocked space) or @ (your starting location).
There will be exactly one @ character in each room description.
Output
A line with an integer: the minimal number of steps necessary to reach the edge of the room, or -1 if no escape is possible.
Sample Input
Sample Output
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<string> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 using namespace std; 9 struct node 10 { 11 int xx; 12 int yy; 13 int pastx; 14 int pasty; 15 int num; 16 }; 17 char mapp[105][105]={'\0'}; 18 int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0}; 19 int sx,sy,h,w,n,mark=0; 20 int pastmapp[105][105][5][5]={0}; 21 int jud(int x,int y,int pastx,int pasty,int dx,int dy,int num) 22 { 23 int mark1=0,mark2=0; 24 if(pastx==0&&pasty==0) 25 { 26 if(mapp[x+dx][y+dy]=='.') 27 return 1; 28 else 29 return 0; 30 }//第一个开始走 31 else 32 { 33 if(mapp[x+dx][y+dy]=='\0')//到达终点没 34 {printf("%d\n",num);mark=1;return 1;} 35 if(x+dx>0&&x+dx<=h&&y+dy>0&&y+dy<=w&&mapp[x+dx][y+dy]=='.') 36 { 37 if(pastx==0&&pasty==1)mark1=1; 38 else if(pastx==0&&pasty==-1)mark1=2; 39 else if(pastx==1&&pasty==0)mark1=3; 40 else mark1=4; 41 42 if(dx==0&&dy==1)mark2=1; 43 else if(dx==0&&dy==-1)mark2=2; 44 else if(dx==1&&dy==0)mark2=3; 45 else mark2=4; 46 47 if(pastmapp[x][y][mark1][mark2]) 48 return 0; 49 else 50 pastmapp[x][y][mark1][mark2]=1; 51 52 if(dx!=pastx||dy!=pasty) 53 return 1; 54 else 55 { 56 if((dx==0&&dy==1)||(dx==0&&dy==-1)) 57 { 58 if(mapp[x+1][y]=='#'&&mapp[x-1][y]=='#') 59 return 1; 60 return 0; 61 } 62 else 63 { 64 if(mapp[x][y+1]=='#'&&mapp[x][y-1]=='#') 65 return 1; 66 return 0; 67 } 68 } 69 } 70 else 71 return 0; 72 } 73 } 74 int jud2(int px,int py,int dx,int dy) 75 { 76 if(px==0&&py==0) 77 return 0; 78 if(px==0&&py==-1&&dx==0&&dy==1) 79 return 1; 80 else if(px==0&&py==1&&dx==0&&dy==-1) 81 return 1; 82 else if(px==1&&py==0&&dx==-1&&dy==0) 83 return 1; 84 else if(px==-1&&py==0&&dx==1&&dy==0) 85 return 1; 86 else 87 return 0; 88 } 89 void bfs(int x,int y) 90 { 91 int i,j; 92 node temp,temp2; 93 queue<node>q; 94 mark=0; 95 temp.xx=x; 96 temp.yy=y; 97 temp.pastx=0; 98 temp.pasty=0; 99 temp.num=0; 100 q.push(temp); 101 while(!q.empty()) 102 { 103 if(mark==1) 104 break; 105 temp=q.front(); 106 q.pop(); 107 for(i=0;i<4;i++) 108 { 109 if(jud2(temp.pastx,temp.pasty,dx[i],dy[i]))//判是不是往回走的方向 110 continue; 111 if(jud(temp.xx,temp.yy,temp.pastx,temp.pasty,dx[i],dy[i],temp.num)) 112 { 113 if(mark==1) 114 break; 115 temp2.xx=temp.xx+dx[i]; 116 temp2.yy=temp.yy+dy[i]; 117 temp2.pastx=dx[i]; 118 temp2.pasty=dy[i]; 119 temp2.num=temp.num+1; 120 q.push(temp2); 121 } 122 } 123 if(mark==1) 124 break; 125 } 126 if(mark==0) 127 printf("-1\n"); 128 } 129 int main() 130 { 131 int i,j,mark3=0; 132 scanf("%d",&n); 133 while(n--) 134 { 135 scanf("%d%d",&h,&w); 136 getchar(); 137 for(i=1;i<=h;i++) 138 { 139 for(j=1;j<=w;j++) 140 scanf("%c",&mapp[i][j]); 141 getchar(); 142 } 143 for(i=1;i<=h;i++) 144 for(j=1;j<=w;j++) 145 if(mapp[i][j]=='@') 146 {sx=i;sy=j;break;} 147 //printf("%d%d",sx,sy); 148 mark3=0; 149 for(i=0;i<4;i++) 150 {if(mapp[sx+dx[i]][sy+dy[i]]=='\0') 151 {printf("0\n");mark3=1;break;} 152 if(mark3) 153 break;} 154 if(mark3) 155 continue; 156 bfs(sx,sy); 157 for(i=1;i<=h;i++) 158 for(j=1;j<=w;j++) 159 for(int q=1;q<=4;q++) 160 for(int p=1;p<=4;p++) 161 pastmapp[i][j][p][q]=0; 162 memset(mapp,'\0',sizeof(mapp)); 163 } 164 return 0; 165 }
第三题是strange left,也就是用最基本的BFS就能解的题目,不多说,只需要判重是否走过这一层就行了。
Description
Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button "UP" or "DOWN"?
Input
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,....kn.
A single 0 indicate the end of the input.
Output
Sample Input
Sample Output
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<string> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 int line[205]; 10 int main() 11 { 12 int a,b,n,temp,tempnum,i,mark; 13 while(scanf("%d",&n)&&n!=0) 14 { 15 int marking[205]={0}; 16 queue<int>q,num; 17 mark=0; 18 scanf("%d%d",&a,&b); 19 for(i=1;i<=n;i++) 20 scanf("%d",&line[i]); 21 if(a==b) 22 {printf("0\n");continue;} 23 q.push(a); 24 num.push(0); 25 while(!q.empty()) 26 { 27 temp=q.front(); 28 tempnum=num.front(); 29 q.pop();num.pop(); 30 if((temp+line[temp]==b||temp-line[temp]==b)&&(temp+line[temp]<=n||temp-line[temp]>0)) 31 { 32 mark=1;printf("%d\n",tempnum+1);break; 33 } 34 if(temp+line[temp]<=n) 35 { 36 if(marking[temp+line[temp]]==0) 37 { 38 q.push(temp+line[temp]); 39 num.push(tempnum+1); 40 } 41 } 42 if(temp-line[temp]>0) 43 { 44 if(marking[temp-line[temp]]==0) 45 { 46 q.push(temp-line[temp]); 47 num.push(tempnum+1); 48 } 49 } 50 marking[temp]=1; 51 } 52 if(!mark) 53 printf("-1\n"); 54 } 55 return 0; 56 }
第四题是翻纸牌游戏,翻一个纸牌,会依次带动左右两张纸牌翻动,本意应该是要用数字来表示状态,然后用位运算BFS,但是其实用贪心的算法能0ms过,因为每个纸牌只有翻偶数次的结果是一样的,所以每个纸牌都只有翻与不翻的区别。从左往右依次递归。
需要注意的是,第一个纸牌仍然需要分类翻和不翻,可以做一个假想,比如在第一个纸牌的左边还有一张虚拟纸牌,因为虚拟纸牌的状态不定,所以导致第一张纸牌可能会翻和不翻,这个和他本身是什么颜色是没有关系的,因为第一张纸牌翻不翻与虚拟纸牌的颜色有关系。
Description
Input
Output
Sample Input
Sample Output
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<string> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #define inf 100000 9 using namespace std; 10 char a[25],b[25]; 11 int main() 12 { 13 while(scanf("%s",a)!=EOF) 14 { 15 int i=0,j,t=strlen(a),time=0,mark=0,mark2=0,time2=0,temp1,add=0; 16 if(t==1) 17 { 18 if(a[t-1]=='0') 19 printf("0\n"); 20 else 21 printf("1\n"); 22 continue; 23 } 24 for(i=0;i<t;i++) 25 b[i]=a[i]; 26 if(a[0]=='1') 27 a[0]='0'; 28 else 29 a[0]='1'; 30 if(a[1]=='1') 31 a[1]='0'; 32 else 33 a[1]='1';//翻第一个 34 time++; 35 if(a[0]=='1') 36 i=0; 37 else 38 i=1; 39 for(i;i<t;i++) 40 { 41 mark=0; 42 if(a[i]=='1') 43 { 44 if(i+1<t) 45 { 46 mark=1; 47 if(a[i+1]=='1') 48 a[i+1]='0'; 49 else 50 a[i+1]='1'; 51 } 52 if(i+2<t) 53 { 54 if(a[i+2]=='1') 55 a[i+2]='0'; 56 else 57 a[i+2]='1'; 58 } 59 if(mark) 60 { 61 time++; 62 a[i]='0'; 63 } 64 } 65 } 66 if(a[t-1]!='0'||a[0]=='1') 67 {time=inf;} 68 for(i=0;i<t;i++) 69 { 70 mark=0; 71 if(b[i]=='1') 72 { 73 if(i+1<t) 74 { 75 mark=1; 76 if(b[i+1]=='1') 77 b[i+1]='0'; 78 else 79 b[i+1]='1'; 80 } 81 if(i+2<t) 82 { 83 84 if(b[i+2]=='1') 85 b[i+2]='0'; 86 else 87 b[i+2]='1'; 88 } 89 if(mark) 90 { 91 b[i]=='0'; 92 time2++; 93 } 94 } 95 } 96 if(b[t-1]!='0') 97 time2=inf; 98 if(time==inf&&time2==inf) 99 printf("NO\n"); 100 else 101 {printf("%d\n",time<time2?time:time2);} 102 } 103 return 0; 104 }
第五题是经典的搜索题,sticks,给定一些不同长度的棍子,搜索拼成一组相同长度的棍子的最小值.
整体思路就是先确定结果的范围,因为结果如果分一组,那就不必讨论,做个特判就好,如果要分组的话,至少分两组,所以min(len)<=ans<=sum/2
然后确定一个ans后,进入DFS,枚举状态,这里需要大量的剪枝有六个剪枝。
1.相同长度的棍子,当前这根没被选上,那么直接跳到下一根长度不同的开始。
2.如果该棍子是拼接组合的第一根,如果不成功则说明上一组的棍子拼接有问题,不需要继续递归找,直接回溯上一根。
基本最强力的简直就是这两个,还有一些就是简单的判重,长度超了不能放进来,被用过的不能放进来.
注意!递归如果已经完成一根,那么pos位置要回到第一根开始重新找,而不是在当前这个位置继续,因为前面还有可能没组合上的,当然首先要排序。
Description
Input
Output
Sample Input
Sample Output
1 #include<iostream> 2 #include<stdio.h> 3 #include<string> 4 #include<string.h> 5 #include<cmath> 6 #include<queue> 7 #include<stack> 8 #include<algorithm> 9 using namespace std; 10 int len[100]={0},n,vis[100]={0},ans,requirenum; 11 bool cmp(int a,int b) 12 { 13 return a>b; 14 } 15 bool dfs(int pos,int sum,int num) 16 { 17 if(num==requirenum)///走到终点 18 { 19 return true; 20 } 21 for(int i=pos;i<n;i++) 22 if(!vis[i]&&(sum+len[i])<=ans)///没用过这一根,而且长度小于等于目标长度 23 { 24 //if(i==0||(i>=1&&len[i-1]==len[i]&&vis[i-1])||(len[i-1]!=len[i]))///上一根和它相同长度的要被用过 25 //{ 26 if((sum+len[i])==ans) 27 { 28 vis[i]=1; 29 if(dfs(0,0,num+1))///完成一根棍子回到0位 30 return true; 31 vis[i]=0; 32 return false;///说明当前这根已经完成棍子组合不行,不是这么组合的 33 } 34 else 35 { 36 vis[i]=1; 37 if(dfs(i+1,sum+len[i],num)) 38 return true; 39 vis[i]=0; 40 if(!sum) 41 return false;///如果这根是放入组合的第一根,并且不能完成,那么说明上一个组合有问题,回溯 42 43 while(len[i]==len[i+1])///当前这根不行,那么下面相同长度的几根也都不行,直接跳到不同的开始 44 i++; 45 } 46 //} 47 } 48 return false; 49 } 50 int main() 51 { 52 int t,num,i,j,sum,mark; 53 while(scanf("%d",&n)&&n!=0) 54 { 55 sum=0;mark=0; 56 for(i=0;i<n;i++) 57 {scanf("%d",&len[i]);sum+=len[i];} 58 sort(len,len+n,cmp); 59 for(ans=len[n-1];ans<=sum/2;ans++) 60 { 61 if(!(sum%ans))///能整除 62 { 63 requirenum=sum/ans;///一共需要多少根一样的棒子 64 memset(vis,0,sizeof(vis)); 65 if(dfs(0,0,0))///从0位置开始,当前凑的长度为0,现在凑齐了0根 66 {printf("%d\n",ans);mark=1;break;} 67 } 68 } 69 if(!mark) 70 printf("%d\n",sum); 71 memset(len,0,sizeof(len)); 72 } 73 return 0; 74 }