CCF CSP认证——201312

 


 
 

  

201312-1 出现次数最多的数

题目链接

1

数据量较小,且数据范围也比较小。可以直接暴力,通过设置数组记录下标数据出现的次数,最后遍历记录数组获取出现最多出现次数的数字。

#include<iostream>
using namespace std;

int main(){
    
    //暴力 
	int n, flag[10001] = {
    
    0};
	scanf("%d", &n);
	for(int i = 0; i < n; i ++){
    
    
		int a;
		scanf("%d", &a);
		flag[a] ++;
	}
	int m = 0;
	for(int i = 1; i <= 10000; i ++)
		if(flag[m] < flag[i])
			m = i;
	printf("%d", m);
	return 0;
}

 
 

 
 

 
 

201312-2 ISBN号码

题目链接
2

简答题
挨个接受ISBN号码或者分四个数接收都可以。

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;

int main(){
    
    //注意标识码为X(也就是10)的情况 
	int a[10], b = 0;
	char c;
	scanf("%1d-%1d%1d%1d-%1d%1d%1d%1d%1d-%c", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &a[8], &c);
	for(int i = 0; i < 9; i ++)
		b += a[i] * (i + 1);
	b %= 11;
	if(b == (c == 'X' ? 10 : c - '0'))
		printf("Right");
	else
		printf("%1d-%1d%1d%1d-%1d%1d%1d%1d%1d-%c", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], b == 10 ? 'X' : b + '0');
	return 0;
}

 
 

 
 

 
 

201312-3 最大的矩形

题目链接
3


数据量较少,可以直接暴力求解。
时间复杂度:O(n2)

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;

int main(){
    
    //暴力 
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	for(int i = 0; i < n; i ++){
    
    
		int t = a[i];
		for(int j = i; j < n; j ++){
    
    
			t = min(t, a[j]);
			m = max(m, (j - i + 1) * t);
		}
	}
	printf("%d", m);
	return 0;
}


单调栈(递增)
通过单调递增栈实现

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;

int main(){
    
    //单调栈(递增)
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	a[n] = 0;
	stack<int> s;
	for(int i = 0; i <= n; i ++){
    
    
		if(s.empty() || a[s.top()] <= a[i])
			s.push(i);
		else{
    
    
			int t = 0;
			while(!s.empty() && a[s.top()] > a[i]){
    
    
				t = s.top();
				s.pop();
				m = max(m, (i - t) * a[t]);//i - t指的是当前矩阵的宽度,a[t]是当前高度
				//实现单调递增栈
			} 
			s.push(t);
			a[t] = a[i];
		}
	}
	printf("%d", m);
	return 0;
}

关键应该是下述两行代码难以理解
s.push(t);
a[t] = a[i];
为什么要将最后出栈的位置再次入栈呢?因为构建的是递增栈所以前面栈的那些高度也是可以达到当前的高度要求的,所以将最后出栈的位置入栈就可以将前面的面积留存,不至于出现面积损失。如下所示。
分析


单调栈

#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;

int main(){
    
    //单调栈 
	int n, a[1000], m = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i ++)
		scanf("%d", &a[i]) ;
	a[n] = 0;
	stack<int> s;
	for(int i = 0; i <= n; i ++){
    
    
		if(s.empty() || a[s.top()] < a[i])
			s.push(i);
		else{
    
    
			int t = s.top();
			s.pop();
			int area = a[t] * (s.empty() ? i : i - s.top() - 1);
			m = max(m, area);
			-- i;//不移动i,后面还有有个 i++ 
		}
	}
	printf("%d", m);
	return 0;
}

 
 

 
 

 
 

201312-4 有趣的数

题目链接
4

动态规划
第n位所放置的数一定与前n-1位放置的数有关(6种情况)
前i位处于该状态个数 状态(全为) 前i+1位处于该状态个数

状态 数字 转移方程 情况分析
a 2 1 如果前i+1位为2,则前i位一定为2
b 2,0 b*2+a 如果前i+1位为2,0,则
    前i位全为2,第i+1位为0
    前i位为2,0混合串,第i+1位为2或0
c 2,3 c+a 如果前i+1位为2,3,则
    前i位全为2,第i+1位为3
    前i位为2,3混合串,第i+1位为3
d 2,0,1 d*2+b 如果前i+1位为2,0,1,则
    前i位为2,0,第i+1位为1
    前i位为2,0,1,第i+1位为2或1
e 2,0,3 e*2+c+b 如果前i+1位为2,0,3,则
    前i位为2,0,第i+1位为3
    前i位为2,3,第i+1位为0
    前i位为2,0,3,第i+1位为0或3
f 2,0,3,1 f*2+e+d 如果前i+1位为2,0,3,1,则
    前i位为2,0,1,第i+1位为3
    前i位为2,0,3第i+1位为1
    前i位为2,0,3,1第i+1位为1或3
#include<iostream>
using namespace std;

long long a, b, c, d, e, f; 

int main(){
    
    
	//第n位所放置的数一定与前n-1位放置的数有关(6种情况) 
	/*前i位处于该状态个数	状态(全为)	前i+1位处于该状态个数*/
	a = 1;
	b = c = d = e = f = 0;
	int n;
	scanf("%d", &n);
	for(int i = 1; i < n; i ++){
    
    
		long long xb = b * 2 + a;
		long long xc = c + a;
		long long xd = d * 2 + b;
		long long xe = e * 2 + b + c;
		long long xf = f * 2 + d + e;
		
		b = xb % 1000000007LL;
		c = xc % 1000000007LL;
		d = xd % 1000000007LL;
		e = xe % 1000000007LL;
		f = xf % 1000000007LL;
	}
	printf("%lld", f);
	return 0;
}

 
 

 
 

 
 

201312-5 I’m stuck!

题目链接
5

dfs深度优先搜索(暴力)
通过dfs将所有S可以到达的点都标记上
同通过dfs将S不能达到的点都试一下是否可以到达T,不可以到达则数量+1

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;

int n, m;//地图行列数
bool flag[50][50], flag1[50][50];//flag1存储S可以到达的点,true为可以到达的点,false为不可以到达的点
int d[][2] = {
    
    -1, 0, 1, 0, 0, -1, 0, 1};//移动方向
vector<string> map;//存储地图
int si, sj, ti, tj;//存储S和T的位置

void dfs(int x, int y){
    
    //深度优先搜索
	int xx, yy;
	flag[x][y] = 1;//标记该点已到达
	
	if(map[x][y] == '+' || map[x][y] == 'S' || map[x][y] == 'T'){
    
    //可以上下左右移动的点
		for(int i = 0; i < 4; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')//可以走的点
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '-'){
    
    //可以左右移动的点
		for(int i = 2; i < 4; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '|'){
    
    //可以上下移动的点
		for(int i = 0; i < 2; i ++){
    
    
			xx = x + d[i][0];
			yy = y + d[i][1];
			if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
				dfs(xx, yy);
		}
	}
	else if(map[x][y] == '.'){
    
    //只能向下移动
		xx = x + d[1][0];
		yy = y + d[1][1];
		if(xx >= 0 && xx < n && yy >= 0 && yy < m && !flag[xx][yy] && map[xx][yy] != '#')
			dfs(xx, yy);
	}
}

int main(){
    
    //暴力 
	scanf("%d %d", &n, &m);
	for(int i = 0; i < n; i ++){
    
    
		string s;
		cin >> s;
		map.push_back(s);
	}
	for(int i = 0; i < n; i ++)
		for(int j = 0; j < m; j ++)
			if(map[i][j] == 'S')
				si = i, sj = j;
			else if(map[i][j] == 'T')
				ti = i, tj = j;
	
	dfs(si, sj);
	memcpy(flag1, flag, sizeof(flag));
	
	if(flag[ti][tj]){
    
    
		int cnt = 0;
		for(int i = 0; i < n; i ++)
			for(int j = 0; j < m; j ++){
    
    
				if(flag1[i][j]){
    
    
					memset(flag, 0, sizeof(flag));
					dfs(i, j);
					if(!flag[ti][tj])
						cnt ++;
				}
			}
		printf("%d", cnt);
	}
	else
		printf("I'm stuck!");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43448856/article/details/127892877