剪格子 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 "); 30 else printf("%d ",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 }
翻硬币 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 }
连号区间数 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 ",res); 27 28 return 0; 29 }
幸运数 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 ",res); 40 41 return 0; 42 }
高僧斗法 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 ",-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 ",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 ", a[i], k ); 44 flag = true; 45 break; 46 } 47 } 48 49 50 if( flag ) break; 51 } 52 } 53 54 return 0; 55 }