2013年12月 CCF CSP 认证 题解

 

 

 


第三题:

试题编号:201312-3
试题名称:最大的矩形
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。



  请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。

输入格式

  第一行包含一个整数n,即矩形的数量(1 ≤ n ≤ 1000)。
  第二行包含n 个整数h1, h2, … , hn,相邻的数之间由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i个矩形的高度。

输出格式

  输出一行,包含一个整数,即给定直方图内的最大矩形的面积。

样例输入

6
3 1 6 5 2 3

样例输出

10

解题思路:

dp[i][j] 首先预处理出 从 i 开始 长度为 j 的最高值。

长度为1时:是每一位的值

 dp[i][1]=cas[i];      

长度大于1时:dp[i][j-1]与cas[i+j-1]比较得到

dp[i][j]=dp[i][j-1]<=cas[i+j-1]?dp[i][j-1]:cas[i+j-1];     

其中 cas 为输入的一维数组 ,i+j-1<=n-1;

然后穷举 根据矩形的面积公式不断更新值,最终得到最大值。

 

参考代码:

#include<stdio.h>
int cas[1010];
int dp[1010][1010];

int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&cas[i]);
	}
	
	for(int i=0;i<n;i++){
		dp[i][1]=cas[i];
	}
	for(int j=2;j<=n;j++) {
		for(int i=0;i+j<=n;i++){
			dp[i][j]=dp[i][j-1]<=cas[i+j-1]?dp[i][j-1]:cas[i+j-1];
		}
	}
	
/*	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			printf("%d ",dp[i][j]);
		}
		puts("\n");
	}
*/	
	int maxn=0;
	for(int len=1;len<=n;len++){
		for(int i=0;i+len-1<=n-1;i++){
			maxn=len*dp[i][len]>maxn?len*dp[i][len]:maxn;
		}
	} 
	printf("%d",maxn);
	return 0;
}

第四题:

试题编号:201312-4
试题名称:有趣的数
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  我们把一个数称为有趣的,当且仅当:
  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。
  因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
  请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

输入格式

  输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。

输出格式

  输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。

样例输入

4

样例输出

3

解题思路:

采用动态规划思想,每一次决策都基于前一次决策的最优解。
即对一个n位数的解都基于前一个n-1位的数的最优解。
我们对一个数的第n位规定一个状态集:即到这一位为止还有几个数字没有使用(我们有0123共四个数)。
根据规则来说,共有6种状态:
  0--用了2,剩0,1,3
       1--用了0,2,剩1,3
       2--用了2,3,剩0,1
       3--用了0,1,2,剩3
       4--用了0,2,3,剩1
       5--全部用了
于是我们需要让用户输入位数,然后声明同等位数的数组,在每个元素里是6种状态中所包含的该状态下的“符合条件的数”的个数。(是二维数组)
然后用动态规划思想从最小位数开始逐层往上计算。

状态图:

参考代码:
 

#include<stdio.h> 
int main()
{
	int i,n;
	long long  dp[1010][10];
	scanf("%d",&n);
	
	for (i=1;i<=n;i++)
	{
		 dp[i][0]=1;	//首位只能为2 
		 dp[i][1]=(dp[i-1][1]*2+dp[i-1][0])%1000000007;
		 dp[i][2]=(dp[i-1][2]+dp[i-1][0])%1000000007;
		 dp[i][3]=(dp[i-1][3]*2+dp[i-1][1])%1000000007;
		 dp[i][4]=(dp[i-1][4]*2+dp[i-1][2]+dp[i-1][1])%1000000007;
		 dp[i][5]=(dp[i-1][5]*2+dp[i-1][4]+dp[i-1][3])%1000000007;
	}
    printf("%lld\n",dp[n][5]);
	
	return 0;
}

 


第五题:

试题编号:201312-5
试题名称:I’m stuck!
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
  '#': 任何时候玩家都不能移动到此方格;
  '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
  '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
  '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
  'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
  此外,玩家不能移动出地图。
  请找出满足下面两个性质的方格个数:
  1. 玩家可以从初始位置移动到此方格;
  2. 玩家可以从此方格移动到目标位置。

输入格式

  输入的第一行包括两个整数R 和C,分别表示地图的行和列数。(1 ≤ R, C ≤ 50)。
  接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个'S'和一个'T'。

输出格式

  如果玩家在初始位置就已经不能到达终点了,就输出“I'm stuck!”(不含双引号)。否则的话,输出满足性质的方格的个数。

样例输入

5 5
--+-+
..|#.
..|##
S-+-T
####.

样例输出

2

样例说明

  如果把满足性质的方格在地图上用'X'标记出来的话,地图如下所示:
  --+-+
  ..|#X
  ..|##
  S-+-T
  ####X

解题思路:

dfs 遍历能够到达的点和能够到达终点的点,最终查找输出。

参考代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 55
using namespace std;
 
int r, c, s, e;
char cas[maxn][maxn];
bool f1[maxn][maxn], f2[maxn][maxn];

bool valiate(int x,int y){
	if (x < 0 || x >= r || y < 0 || y >= c|| cas[x][y] == '#') return false;
	return true;
}

void dfs1(int x, int y)
{
	if(!valiate(x,y)||f1[x][y])	return ;
	f1[x][y] = true;
	if (cas[x][y] == '|') dfs1(x + 1, y), dfs1(x - 1, y);
	else if (cas[x][y] == '-') dfs1(x, y - 1),dfs1(x, y + 1); 
	else if (cas[x][y] == '.')dfs1(x + 1, y);
	else dfs1(x + 1, y), dfs1(x - 1, y), dfs1(x, y - 1), dfs1(x, y + 1);
}

void dfs2(int x,int y){
	if(!valiate(x,y)||f2[x][y])	return;
	f2[x][y] = true;
	if(cas[x-1][y]=='+'||cas[x-1][y]=='|'||cas[x-1][y]=='.'||cas[x-1][y]=='S'||cas[x-1][y]=='T') dfs2(x-1,y);
	if(cas[x+1][y]=='+'||cas[x+1][y]=='|'||cas[x+1][y]=='S'||cas[x+1][y]=='T') dfs2(x+1,y);
	if(cas[x][y+1]=='+'||cas[x][y+1]=='-'||cas[x][y+1]=='S'||cas[x][y+1]=='T') dfs2(x,y+1);
	if(cas[x][y-1]=='+'||cas[x][y-1]=='-'||cas[x][y-1]=='S'||cas[x][y-1]=='T') dfs2(x,y-1);
}

int main(){
	scanf("%d %d",&r,&c);
	char cc;
	int si,sj,ti,tj;
	for (int i = 0; i < r; i++){
		for (int j = 0; j < c; j++){
			scanf("\n%c",&cas[i][j]);
			if(cas[i][j]=='S') si=i,sj=j;
			if(cas[i][j]=='T') ti=i,tj=j;
		}		
	}
//	printf("%d %d %d %d\n",si,sj,ti,tj);
	
	memset(f1,false,sizeof(f1));
	memset(f2,false,sizeof(f2));
	
	dfs1(si,sj),dfs2(ti,tj);
	int sum = 0;
	
	/*
	for (int i = 0; i < r; i++){
		for (int j = 0; j < c; j++)
				printf("%d",f1[i][j]);	
			printf("\n");
			
	}
		for (int i = 0; i < r; i++){
		for (int j = 0; j < c; j++)
				printf("%d",f2[i][j]);	
			printf("\n");
			
	}	*/

	
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			if (f1[i][j] && !f2[i][j]){
				sum++;
				//printf("%d %d\n",i,j);	
			}
	if (f1[ti][tj])	printf("%d\n",sum);
	else printf("I'm stuck!\n");
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值