程序设计——第十二周作业(三维空间找路径、东东扫宿舍、括号匹配)

A必做题

在这里插入图片描述

#include<bits/stdc++.h>
#define MAX_SIZE 1000000
using namespace std;

int n,a[MAX_SIZE],cnt[MAX_SIZE];

int main(){
	while(~scanf("%d",&n)){
		memset(cnt,0,sizeof(cnt));
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		for(int i=0;i<n;i++){
		    cnt[a[i]]++;
		    if(cnt[a[i]]==(n+1)/2){
		        printf("%d\n",a[i]);
		        break;
		    }
		}
	}
} 

B.三维空间找路径

题目描述

zjm被困在一个三维的空间中,现在要寻找最短路径逃生!
空间由立方体单位构成。
zjm每次向上下前后左右移动一个单位需要一分钟,且zjm不能对角线移动。
空间的四周封闭。zjm的目标是走到空间的出口。
是否存在逃出生天的可能性?如果存在,则需要多少时间?
Input:
输入第一行是一个数表示空间的数量。
每个空间的描述的第一行为L,R和C(皆不超过30)。
L表示空间的高度,R和C分别表示每层空间的行与列的大小。
随后L层,每层R行,每行C个字符。
每个字符表示空间的一个单元。’#‘表示不可通过单元,’.‘表示空白单元。
zjm的起始位置在’S’,出口为’E’。每层空间后都有一个空行。
L,R和C均为0时输入结束。
Output:
每个空间对应一行输出。
如果可以逃生,则输出如下
Escaped in x minute(s).
x为最短脱离时间。
如果无法逃生,则输出如下
Trapped!
Sample Input:

    3 4 5
    S….
    .###.
    .##..
    ###.#

    #####
    #####
    ##.##
    ##…

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

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

    0 0 0

Sample Output:

Escaped in 11 minute(s).
Trapped!

思路分析

采用BFS即可,之前接触的都是二维坐标系,方向也只有四个方向+x,-x,+y,-y。这道题目只是换成了三维坐标系,方向有+x,-x,+y,-y,+z,-z。方法很简单,主要是注意输入的时候设计很多字符的输入,注意使用getchar()这一类的语句吞掉回车。

代码实现

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std; 

int dx[]={0,0,0,0,1,-1},dy[]={0,0,1,-1,0,0},dz[]={1,-1,0,0,0,0};//方向:+z -z +y -y +x -x
char a[32][32][32];
int vis[32][32][32],l,r,c,sum=0;//相当于z,x,y
struct pos{
	int x,y,z;
	pos(){};
	pos(int xx,int yy,int zz){
		x=xx,y=yy,z=zz;
	}
	bool operator == (pos &p){
		if(this->x==p.x&&this->y==p.y&&this->z==p.z) return true;
		else return false;
	}
}p[32][32][32];
queue<pos> q;

void BFS(pos s,pos e){//参数为起点和终点 
	q.push(s);
	vis[s.x][s.y][s.z]=1;
	pos init=pos(-1,-1,-1);
	p[s.x][s.y][s.z]=init;//起点之前的位置初始 
	pos tmp;
	int px,py,pz;
	bool have=false;
	while(!q.empty()){
		tmp=q.front();
		q.pop();
		if(tmp==e) {//当前点是终点那么结束循环 
		    have=true;
			break;
		}
		for(int i=0;i<6;i++){//6个方向
		    int tx=tmp.x+dx[i],ty=tmp.y+dy[i],tz=tmp.z+dz[i];
		    if(tx<0||ty<0||tz<0) continue;
		    if(tx>=r||ty>=c||tz>=l) continue;//这里一定要限定范围不然会RE 
		    if(a[tx][ty][tz]!='#'&&vis[tx][ty][tz]!=1){	
				vis[tx][ty][tz]=1;//标记 
				p[tx][ty][tz]=tmp;//记录前一个位置 
				q.push(pos(tx,ty,tz));//入队	
			} 
		}
	}
	if(!have){
	    printf("Trapped!\n");
	    return;
	}
	int nx=e.x,ny=e.y,nz=e.z;
	while(!(p[nx][ny][nz]==init)){//逆向求路径点的个数 
		sum++;
		int tnx=p[nx][ny][nz].x,tny=p[nx][ny][nz].y,tnz=p[nx][ny][nz].z;//这里不要直接拿去赋值给nx,ny,nz 
		nx=tnx;ny=tny;nz=tnz;
	}
	printf("Escaped in %d minute(s).\n",sum);
}

int main(){
	while(~scanf("%d%d%d",&l,&r,&c)){
		getchar();
		if(l==0&&r==0&&c==0) return 0;
		memset(vis,0,sizeof(vis));
		memset(p,-1,sizeof(p));
		while(!q.empty()) q.pop();
		sum=0;
		pos sp,ep;
		for(int i=0;i<l;i++){//高 
		    for(int j=0;j<r;j++){//长 
		        for(int k=0;k<c;k++){//宽 
		            scanf("%c",&a[j][k][i]); 
		            if(a[j][k][i]=='S') sp=pos(j,k,i);//起点位置 
		            if(a[j][k][i]=='E') ep=pos(j,k,i);
		        }
		        getchar();
		    }
		    getchar();
		}
		BFS(sp,ep);
	}
	return 0;
} 

C.东东扫楼

题目描述

东东每个学期都会去寝室接受扫楼的任务,并清点每个寝室的人数。
每个寝室里面有ai个人(1<=i<=n)。从第i到第j个宿舍一共有sum(i,j)=a[i]+…+a[j]个人
这让宿管阿姨非常开心,并且让东东扫楼m次,每一次数第i到第j个宿舍sum(i,j)
问题是要找到sum(i1, j1) + … + sum(im,jm)的最大值。且ix <= iy <=jx和ix <= jy <=jx的情况是不被允许的。也就是说m段都不能相交。
注:1 ≤ i ≤ n ≤ 1e6 , -32768 ≤ ai ≤ 32767 人数可以为负数。。。。(1<=n<=1000000)
Input:
输入m,输入n。后面跟着输入n个ai 处理到 EOF
Output:
输出最大和
Sample Input:

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

Sample Output:

6
8 

思路分析

首先领略题目重点:有一段序列,该序列有n个数字,选m不交叉的子序列,然后相加找最大值。
利用动态规划的思想,定义dp[i][j]表示到第j个数字时取了i个段的最大和,所以有如下状态转移方程dp[i][j]=max(dp[i][j-1]+a[j],dp[i-1][k]+a[j]。当前状态:从前j个数字中取出i段的最大和,上一个最大和状态:从前j-1个数字中取了i段或者从前k个数字中取i-1段。当前状态的最大和正是这两种以上状态的最大值加上当前a[j]。
再进行观察转移过程,就会发现计算dp[i][j]只需要知道dp[i][j-1]和dp[i-1][k]的最大值即可。所以使用另一个一维数组f来记录将从j个元素中取i-1段中的最大和,即状态转移方程:dp[j]=max(dp[j-1]+a[j],f[j-1]+a[j])。

代码实现

#include<bits/stdc++.h> 
using namespace std;

const int maxn=1e6+10,maxm=1e9;
int a[maxn],dp[maxn],f[maxn],m,n;
int res=-maxm; 
// dp记录当前状态即从前数组a前j个数字中取i段的最大和
//f记录从数组a前j个数字中取i-1段的最大和
//max(dp[j])将是答案 

int main(){
	while(~scanf("%d%d",&m,&n)){
		memset(dp,0,sizeof(dp));
		memset(f,0,sizeof(f)); 
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1;i<=m;i++){
			res=-maxm;
			for(int j=i;j<=n;j++){//dp从j个元素中取i段 
				dp[j]=max(dp[j-1]+a[j],f[j-1]+a[j]);//f从j个元素中取i-1段 
				f[j-1]=res;
				res=max(res,dp[j]);//找出dp最大值 
			}
		}
	    printf("%d\n",res);
	}
	return 0;
}

D.括号配对

We give the following inductive definition of a “regular brackets” sequence:
the empty sequence is a regular brackets sequence,
if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences, and
if a and b are regular brackets sequences, then ab is a regular brackets sequence.
no other sequence is a regular brackets sequence
For instance, all of the following character sequences are regular brackets sequences:
(), [], (()), ()[], ()[()]
while the following character sequences are not:
(, ], )(, ([)], ([(]
Given a brackets sequence of characters a1a2 … an, your goal is to find the length of the longest regular brackets sequence that is a subsequence of s. That is, you wish to find the largest m such that for indices i1, i2, …, im where 1 ≤ i1 < i2 < … < im ≤ n, ai1ai2 … aim is a regular brackets sequence.
Given the initial sequence ([([]])], the longest regular brackets subsequence is [([])].
Input:
The input test file will contain multiple test cases. Each input test case consists of a single line containing only the characters (, ), [, and ]; each input test will have length between 1 and 100, inclusive. The end-of-file is marked by a line containing the word “end” and should not be processed.
Output:
For each input case, the program should print the length of the longest possible regular brackets subsequence on a single line.
Sample Input:

((()))
()()()
([]])
)[)(
([][][)
end

Sample Output:

6
6
4
0
6

思路分析

捋清楚题意:给你一个含括号的字符串,求最大匹配的个数。
定义dp[i][j]表示从i到j最大括号匹配数。
若第i个括号无法在[i+1,j]中匹配,那么dp[i][j]=dp[i+1][j]
若在区间[i+1,j]中找到一个k使得和i匹配,区间就被划分为2段,[i+1,k-1],[k+1,j] ,这时候dp[i][j]=max(dp[i][j],dp[i+1][k-1]+dp[k+1][j]+2) 。

代码实现

#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

char s[105];
int dp[105][105],sz;

int main(){
	while(~scanf("%s",s)){
		if(s[0]=='e') return 0;
		memset(dp,0,sizeof(dp));
		sz=strlen(s);
		for(int i=sz-1;i>=0;i--)
		    for(int j=i+1;j<sz;j++){
		    	dp[i][j]=dp[i+1][j];
		    	for(int k=i+1;k<=j;k++){//在[i+1,j]中寻找有没有与之配对的 
		    		if(s[i]=='['&&s[k]==']'||(s[i]=='('&& s[k]==')'))
		    		    dp[i][j]=max(dp[i][j],dp[i+1][k-1]+dp[k+1][j]+2);
				}
			}
	    printf("%d\n",dp[0][sz-1]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值