程序设计week12 必做题

A - 必做题 - 1

在这里插入图片描述

Sample Input
5
1 3 2 3 3
11
1 1 1 1 1 5 5 5 5 5 5
7
1 1 1 1 1 1 1
Sample Output
3
5
1

解题思路

排序后,所有相同的数都挨在一起
记录当前数的个数,当个数大于(n+1)/2时输出
每个数只遍历一次,复杂度为On

代码实现

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int Max = 1e6+ 100;
int n;
int a[Max];
int flag;
int sum;

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
		//	cin>>a[i];
		scanf("%d",&a[i]);
		}
		sort(a,a+n);
		
		flag = a[0];
		sum=1;
		int m = (n+1)/2;
		
		for(int i=1;i<n;i++)
		{
			if(flag==a[i])
			sum++;
			else
			{
				sum=1;
				flag=a[i];
			}
			if(sum>=m)
			{
			//	cout<<a[i]<<endl;
			printf("%d\n",a[i]);
				break;
			}
		}
	}
	return 0;
}

B - 必做题 - 2

在这里插入图片描述

Sample Input
3 4 5
S....
.###.
.##..
###.#

#####
#####
##.##
##...

#####
#####
#.###
####E

1 3 3
S##
#E#
###

0 0 0

Sample Output
Escaped in 11 minute(s).
Trapped!

解题思路

三维数组的bfs
不能移动到有#的,和已经移动过了的地方
用bfs而不用dfs,因为dfs不能保证求出来的是最优解
步数和记忆化用vis记录
具体实现看代码

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
int l,r,c;
char a[35][35][35];    
int vis[35][35][35];
int res;
struct point{
	int _i,_j,_k; //层,行,列 
};

point start,end;   //记录起点和终点的位置
queue<point> q;

void ini();
void bfs();

int main()
{
	while(1)
	{
		scanf("%d%d%d",&l,&r,&c);
		if(l==0&&r==0&&c==0) return 0;
		for(int i=0;i<l;i++)
		{
			for(int j=0;j<r;j++)
			{
				for(int k=0;k<c;k++)
				{
					cin>>a[i][j][k];
					if(a[i][j][k]=='S')
					start._i=i,start._j=j,start._k=k;
					if(a[i][j][k]=='E')
					end._i=i,end._j=j,end._k=k;
				}
			}
		}
		bfs();
		if(vis[end._i][end._j][end._k]>1)  printf("Escaped in %d minute(s).\n",vis[end._i][end._j][end._k]-1);
		if(vis[end._i][end._j][end._k]<=1) printf("Trapped!\n");
		ini();
	}
	return 0;
}

void ini()  //初始化
{
	memset(a,0,sizeof(a));
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
}

void bfs()
{
	int i=start._i,j=start._j,k=start._k;
	vis[i][j][k] = 1;
	q.push(start);
	while(!q.empty())
	{
		point p=q.front(); 
		q.pop();
		if(p._i==end._i&&p._j==end._j&&p._k==end._k) return ;  //到达终点结束
		for(int qi=0;qi<6;qi++)  //上下左右前后 
		{
			point pt;
			if(qi==0)  //上 
			{
				if(p._i+1 < l && vis[p._i+1][p._j][p._k]==0 && a[p._i+1][p._j][p._k]!='#')
				{
					vis[p._i+1][p._j][p._k] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i+1,pt._j=p._j,pt._k=p._k;
					q.push(pt); 
					continue;
				}
				else continue;
			}		
			if(qi==1) //下
			{
				if(p._i-1 >= 0 && vis[p._i-1][p._j][p._k]==0 && a[p._i-1][p._j][p._k]!='#')
				{
					vis[p._i-1][p._j][p._k] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i-1,pt._j=p._j,pt._k=p._k;
					q.push(pt);
					continue; 
				}
				else continue;
			 }
			 if(qi==2) //右
			 {
			 	if(p._k+1 < c && vis[p._i][p._j][p._k+1]==0 && a[p._i][p._j][p._k+1]!='#')
				{
					vis[p._i][p._j][p._k+1] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i,pt._j=p._j,pt._k=p._k+1;
					q.push(pt);
					continue; 
				}
				else continue;
			 }
			 if(qi==3) //左 
			 {
			 	if(p._k-1 >= 0 && vis[p._i][p._j][p._k-1]==0 && a[p._i][p._j][p._k-1]!='#')
				{
					vis[p._i][p._j][p._k-1] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i,pt._j=p._j,pt._k=p._k-1;
					q.push(pt); 
					continue;
				}
				else continue;
			 }
			 if(qi==4) //前
			 {
			 	if(p._j-1 >= 0 && vis[p._i][p._j-1][p._k]==0 && a[p._i][p._j-1][p._k]!='#')
				{
					vis[p._i][p._j-1][p._k] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i,pt._j=p._j-1,pt._k=p._k;
					q.push(pt); 
					continue;
				}
				else continue;
			}
			if(qi==5) //后
			{
				if(p._j+1 < r && vis[p._i][p._j+1][p._k]==0 && a[p._i][p._j+1][p._k]!='#')
				{
					vis[p._i][p._j+1][p._k] = vis[p._i][p._j][p._k]+1;	
					pt._i = p._i,pt._j=p._j+1,pt._k=p._k;
					q.push(pt); 
					continue;
				}
				else continue;
			 }
		}
	}
	return ;	
}

C - 必做题 - 3

在这里插入图片描述

Sample Input
1 3 1 2 3
2 6 -1 4 -2 3 -2 3
Sample Output
6
8 
Hint
数据量很大,需要scanf读入和dp处理。

解题思路

动态规划问题
状态设置  dp[i][j] -----选了j的,分成i段的最大值 
状态转移方程  dp[i][j] = max(dp[i-1][j-1] ,dp[i-1][k]) + a[j]
解释: 状态是选择了j的,所以转移到 dp[i][j]必须要加上 a[j]

分为2种情况:
第一种,a[j]是连着a[j-1]的那一段的
第二种, a[j]是新开的一段,与a[k]有间隔
由上述2种状态转移过来

但是,数据量太大,会爆内存,所以要使用滚动数组
设置一个max1[] 记录上一次的结果
dp[]用来计算这一次的结果

从 i=1滚动到 m 结束,得到的就是分成m段的结果
max1[j-1]是不包括j-1,j-1之前的最大值

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e6+5;

int m,n;
int a[N];
int dp[N];
int max1[N];

int main()
{
	while(scanf("%d %d",&m,&n)!=EOF)
{
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	memset(dp,0,sizeof(dp));
	memset(max1,0,sizeof(max1));	
	int t;
	for(int i=1;i<=m;i++)  //从 分成1段 推到 分成 m段 
	{
		t = -1000000000;
		for(int j=i;j<=n;j++)  //第i次记录在max1中,使用在i+1里面 
		{
			dp[j] = max(dp[j-1],max1[j-1])+a[j];
			max1[j-1]=t;
			t=max(t,dp[j]);
		}
		
	}
	printf("%d\n",t);
}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值