2013 蓝桥杯B组C++

剪格子 https://www.dotcpp.com/oj/problem1432.html

解题思路:dfs从左上角向四个方向搜索,用bool数组判断保证在一次搜索中不重复遇到同一顶点。

注意:输入是先列后行

实现代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int INF = 1e9;
 6 const int Max_N = 10;
 7 
 8 int n,m;
 9 int number[Max_N][Max_N];
10 bool visited[Max_N][Max_N];
11 int sum;
12 int res = INF;
13 
14 void dfs(int x, int y, int num, int cnt);
15 
16 int main()
17 {
18     scanf("%d%d",&m,&n);
19     for( int i=0; i<n; i++ )
20     {
21         for( int j=0; j<m; j++ )
22         {
23             scanf("%d",&number[i][j]);
24             sum += number[i][j]; 
25         }
26     }
27     
28     dfs(0,0,0,0);
29     if( res==INF )    printf("0\n");
30     else            printf("%d\n",res);
31     
32     return 0;
33 }
34 
35 void dfs(int x, int y, int num, int cnt)
36 {
37     if( x<0 || x>=n || y<0 || y>=m || num>sum/2 || cnt>=res || visited[x][y] )
38         return;
39     
40     visited[x][y] = true;
41     num += number[x][y];
42     cnt++;
43     
44     if( num==sum/2 )
45     {
46         res = min( res, cnt );
47     }
48     
49     dfs(x+1,y,num,cnt);
50     dfs(x-1,y,num,cnt);
51     dfs(x,y+1,num,cnt);
52     dfs(x,y-1,num,cnt);
53     
54     visited[x][y] = false;
55 }
View Code

翻硬币  https://www.dotcpp.com/oj/problem1453.html

解题思路:开关问题

  1.硬币区间翻转的顺序对结果无影响

  2.同一个区间([i,i+1])重复翻是多余操作

  所以我们规定从左到右判断,若不同则必须翻转,再此之后该位置就不需要考虑,问题规模-1。

实现代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<string> 
 4 using namespace std;
 5 
 6 void clip(string &s, int i)
 7 {
 8     if( s[i]=='*' )    s[i] = 'o';
 9     else            s[i] = '*';
10 }
11 
12 int main()
13 {
14     string s1,s2;
15     cin>>s1>>s2;
16     
17     int res = 0;
18     for( int i=0; i<s1.length()-1; i++ )
19     {
20         if( s1[i]!=s2[i] )
21         {
22             clip(s1,i);
23             clip(s1,i+1);
24             res++;
25         }
26     }
27     cout<<res<<endl;
28     
29     return 0;
30 }
View Code

连号区间数  https://www.dotcpp.com/oj/problem1456.html

解题思路:解题的关键是连号区间数的判断--区间最大值与最小值之差是否等于区间长度。

实现代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int Max_N = 5000;
 6 
 7 int N;
 8 int p[Max_N];
 9 
10 int main()
11 {
12     scanf("%d",&N);
13     for( int i=0; i<N; i++ )    scanf("%d",&p[i]);
14     
15     int res = N; //区间长度为1 
16     for( int i=0; i<N-1; i++ )
17     {
18         int min_p = p[i], max_p = p[i];  //区间[i,j]的两个极值 
19         for( int j=i+1; j<N; j++ )
20         {
21             min_p = min( min_p, p[j] );
22             max_p = max( max_p, p[j] );
23             if( (max_p-min_p) == (j-i) )    res++; //满足条件 
24         }
25     }
26     printf("%d\n",res);
27     
28     return 0;
29 }
View Code

幸运数  https://www.dotcpp.com/oj/problem1441.html

解题思路:暴力求解,简化之处:用step记录从1开始没被删除数字的个数,若step%cur(当前幸运数)则删除当前遍历的数字。

实现代码

 1 #include<cstdio>
 2 #include<cstring>
 3 
 4 const int Max_N = 1000000;
 5 
 6 int m,n;
 7 bool dp[Max_N+1]; //dp[i] = false表示i被删除 
 8 
 9 int main()
10 {
11     int m,n;
12     scanf("%d%d",&m,&n);
13     
14     memset(dp,true,sizeof(dp));
15     int cur = 2;
16     while( cur<=n )
17     {
18         int step = 0;
19         for( int i=1; i<=n; i++ )
20         {
21             if( dp[i]==true )
22             {
23                 step++;
24                 if( step%cur==0 )
25                 {
26                     dp[i] = false;
27                 }
28             }
29         }
30         cur++;
31         while( !dp[cur] ) cur++; 
32     }
33     
34     int res = 0;
35     for( int i=m+1; i<n; i++ )
36     {
37         if( dp[i] )    res++;
38     }
39     printf("%d\n",res);
40     
41     return 0;
42 }
View Code

高僧斗法  https://www.dotcpp.com/oj/problem1459.html

解题思路:解题Nim博弈问题,Nim博弈问题:参考  https://www.cnblogs.com/jiangjun/archive/2012/11/01/2749937.html

  Nim博弈问题说的是有几堆石子堆,两人轮流在任意石堆拿大于1个石子,最后拿光者得胜。博弈问题的结论是将所有石子堆数目异或,若为0则先手负,否则先手胜。

对于先手负的一方即使尽量想破坏局势,先手胜的一方只要每次都在取后保证局面仍然是胜局势即可.

  应用于本题:

  将小和尚两两配对,如{a1, a2, a3, a4 } 将(a1,a2)与(a3,a4)配对,其间隔看作可以取的石子,最后取完者胜。我的理解是对于必胜的策略其先后对结果无影响,那么可以先将处于高台阶的a3取到最上面,之后

取a1,a2,此时a2向上多少a1也可向上多少,a2与a3之间的间隔对结果无影响。(还不是特别清晰)

  对每个石子堆的数目遍历,直到与其他石子堆异或的结果异或为0.

  注意:每个石子堆数目既可以增加也可以减少!

实现代码:

 1 #include<cstdio>
 2 
 3 const int Max_N = 100;
 4 
 5 int a[Max_N];
 6 int num[Max_N];
 7 
 8 int main()
 9 {
10     int index = 0; 
11     while( scanf("%d",&a[index])!=EOF )
12         index++;
13     
14     int xor_ = 0; 
15     for( int i=0; i<index-1; i+=2 )
16     {
17         num[i/2] = a[i+1] - a[i] - 1; //石子堆 两两配对 
18         xor_ ^= num[i/2]; //所有石子堆异或结果 
19     }
20     
21     if( xor_==0 ) //必败 
22     {
23         printf("%d\n",-1);
24     }
25     else
26     {
27         bool flag = false;
28         for( int i=0; i<index-1; i++ )
29         {
30             int x = num[i/2]^xor_;//a^b^a = b x为除该堆外其他堆异或结果 
31             for( int k=a[i]+1; k<a[i+1]; k++ )
32             {
33                 /* 两个堆之间的num[i]可以增大/减小 */
34                 /* 若a增大 b-a减小  若b增大 b-a增大 */
35                 if( i%2==0 && ((a[i+1]-k-1)^x)==0 )
36                 {
37                     printf("%d %d\n",a[i], k );
38                     flag = true;
39                     break;
40                 }
41                 else if( i%2==1 && ((k-a[i-1]-1)^x)==0 )
42                 {
43                     printf("%d %d\n", a[i], k );
44                     flag = true;
45                     break;
46                 }
47             }
48         
49             
50             if( flag )    break;
51         }
52     }
53     
54     return 0;
55 }
View Code

 

 

  

 

posted @ 2021-03-10 10:04  代码改变头发  阅读(44)  评论(0编辑  收藏  举报