欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

程序设计思维与实践第十一十二周实验小结

程序员文章站 2022-03-18 16:15:34
...

11周作业
A题
房子价格是 200万,以每年百分之 K增长,每年积攒 N万,问第几年能够买下这套房子。
第一年积攒N万,房价200万;第二年积攒2N万,房价200(1+K)万,第三年积攒3N万,房价200(1+K)^2 万 ……每一年都比较积攒数与房子价格,当积攒数大于等于房子价格时,为可以购买。当超过限定时间时视为不可购买。

#include<iostream> 

using namespace std; 
  int main(){
  int N;
  double K;
  double price=200.0;
  int year=1,flag=0;
  cin>>N>>K;
  K=K/100.00;
  while(flag==0&&year<=20){
  	if(price<=year*N){flag=1;}
  	else {price=price+price*K;year++;}
  }
  if(flag==1){cout<<year<<endl;}
  else        {cout<<"Impossible"<<endl;}
  return 0;}

B题
n^2个同学排列成一个 n∗n的方阵,用 0 表示男生,用 1表示女生。给定两种方阵方案,判断前一种方阵能否旋转为后一种方阵。
不需要翻转:前一方阵的任意位置的值都与后一方阵对应位置的值相等。
顺时针旋转九十度:前一方阵第i行第j个元素与后一方阵第n-1-i列第j个元素对应相等。
顺时针旋转一百八十度:前一方阵第i行第j个元素与后一方阵第n-1-i行第n-j-1个元素对应相等。
顺时针旋转二百七十度:前一方阵第i行第j个元素与后一方阵第i列第n-j-1个元素对应相等。
不符合上述情况则不能旋转。

#include<iostream> 

using namespace std; 
int a[20][20];
int b[20][20];
  int main(){
  int n;
  cin>>n;
  for(int i=0;i<n;i++){
  	for(int j=0;j<n;j++){
  		cin>>a[i][j];
	  }
  }
  for(int i=0;i<n;i++){
  	for(int j=0;j<n;j++){
  		cin>>b[i][j];}}
  	int x=0;
  for(int i=0;i<n;i++){
  	for(int j=0;j<n;j++){
  		if(a[i][j]!=b[i][j]){
  			x=-1;
  			break;
		  }}}
  if(x==-1){
  	x=1;
  	for(int i=0;i<n;i++){
  	  for(int j=0;j<n;j++){
  		if(a[i][j]!=b[j][n-1-i]){
  			x=-1;
  			break;
		  }}}
  }
  if(x==-1){
  	x=2;
  	for(int i=0;i<n;i++){
  	  for(int j=0;j<n;j++){
  		if(a[i][j]!=b[n-1-i][n-1-j]){
  			x=-1;
  			break;
		  }}}
  }
  if(x==-1){
  	x=3;
  	for(int i=0;i<n;i++){
  	  for(int j=0;j<n;j++){
  		if(a[i][j]!=b[n-1-j][i]){
  			x=-1;
  			break;
		  }}}
  }
  cout<<x<<endl;
  return 0;}

C题
给定明文密文对应规则,对密文解密得到明文。
由题目所给对应规则可知,对于大部分明文字母,其密文是其之后第五个字母。之所以是大部分,是因为V-Z不存在之后五位的字母。我们按照次序给其进行A-E的密文分配。由此我们得知明文密文对应规则为密文=第(明文+5)%26位字母,当密文大于明文时,明文=第(密文-5)%26位字母,反之,明文=第(密文+26-5)%26位字母。由对应规则得到明文。

#include<iostream> 
#include<string>
#include<string.h>
#include<stdio.h>
using namespace std; 

  int main(){
  	string s;
  	getline(cin,s);
  	for(int i=0;i<s.length();i++){
  		if(s[i]>='A'&&s[i]<='E'){
  			s[i]=s[i]+26-5;
		  }
		else if(s[i]>='F'&&s[i]<='Z'){
			s[i]=s[i]-5;
		}
	  }
	cout<<s<<endl;
  }

D题
找到一段最长的序列,该序列中1的数量等于2的数量,且前一半全是一种,后一半全是另外一种。
对于任意一段全为1的序列,它可以与其之前一段全为2的序列组合,也可以与其之后一段全为2的序列组合;对于全为2的序列也是同样的道理。由一段全为1的序列和一段全为2的序列组成的合法序列的最大长度取决于两段序列中长度较小者。例如,111122最长合法序列长度为4,为序列2的两倍。因此,我们每找到一种组合,就由该组合下较短序列的长度确定组合中合法序列的最大长度。遍历所有组合,我们便找到了最长的合法序列。

#include<iostream> 

using namespace std; 

  int main(){
  	int n;
  	cin>>n;
  	int sum1=0,sum2=0,num=0,max=0,pre=0;
  	for(int i=0;i<n;i++){
  		cin>>num;
		if(num==1){
			if(pre!=2){sum1++;}
			else {
				if(sum1==0){sum1++;}
				else{
					if(sum1>=sum2){if(max<2*sum2) max=2*sum2;}
					else if(sum1<sum2){if(max<2*sum1) max=2*sum1;}
					sum1=1;
				}}}
		if(num==2){
			if(pre!=1){sum2++;}
			else {
				if(sum2==0){sum2++;}
				else{
					if(sum1>=sum2){if(max<2*sum2) max=2*sum2;}
					else if(sum1<sum2){if(max<2*sum1) max=2*sum1;}
					sum2=1;
				}}}
		pre=num;	
	  }
	  if(sum1>=sum2){if(max<2*sum2) max=2*sum2;}
	  else if(sum1<sum2){if(max<2*sum1) max=2*sum1;}
	cout<<max<<endl;
  }

E题
给定所请求的现金量 纸币面额和该纸币的数量。输出不超过现金量的最大可支付数。
由于给定纸币面额的同时,限定了该纸币的数量。所以这道题是一道典型的多重背包问题,将不同纸币的数量进行二进制拆分转换为0,1背包问题来解决。为节约空间,0,1背包采用逆序。

#include<iostream>
#include<cstring>

using namespace std;

int cash,N,n[11],d[11],c[10001],s[100010];

int main(){
    while(cin>>cash){
    	cin>>N; 
        for (int i=0;i<N;i++)
            cin>>n[i]>>d[i];
        int cnt=0;
        for (int i=0;i<N;i++){
            int t=n[i];
            for (int k=1;k<=t;k<<=1){
                c[cnt]=k*d[i];
                t-=k;
                cnt++;
            }
            if(t>0){
                c[cnt]=t*d[i];
                cnt++;
            }
        }
        for(int i=0;i<cnt;i++)//普通01
            for(int j=cash;j>=c[i];j--)
                s[j]=max(s[j],s[j-c[i]]+c[i]);
        cout<<s[cash]<<endl;
        memset(s,0,sizeof(s));
    }

    return 0;
}

F题
给定开车时间,唱片数量和每一张唱片的播放长度。输出总时长不超过开车时间的听歌方案与时长。
由于开车时间相对较长,而唱片数量相对较少,我将这道题视为超大背包来解决。而由于唱片数量足够小,所以无需进行拆分,所以简单用枚举子集的办法就可以得到最长时长和此时的方案。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;


void dfs(int num,int *a,int *b,int *c,int N,int M,int sum,int flag,int &max){
	if(flag==0&&sum<=N){
		
	if(num<M){
	b[num]=0;
	dfs(num+1,a,b,c,N,M,sum,flag,max);
	
	b[num]=1;
	sum=sum+a[num];
	dfs(num+1,a,b,c,N,M,sum,flag,max);}
	else {
		if(max<sum&&sum<=N){
		max=sum;
		for(int i=0;i<M;i++){c[i]=b[i];}
		flag=1;}
	}}}
int main(){
	int N;
	while(scanf("%d",&N)!=EOF){
		int M;
		cin>>M;
		int a[M];
		int b[M];
		int c[M];
		for(int i=0;i<M;i++){
			cin>>a[i];
			b[i]=0;
		}
	int sum=0,flag=0,max=0;
	dfs(0,a,b,c,N,M,sum,flag,max);
	for(int i=0;i<M;i++){
		if(c[i]==1){
			cout<<a[i]<<" ";
		}
	}
	cout<<"sum:"<<max<<endl;
}} 

11周模拟题
T1
给定一个序列,输出序列的段数。(段定义:连续的相同的最长整数序列)
从第二个元素开始遍历,如果与前一位置元素相同,证明在同一段中,段数不变。反之,则在不同段中,段数加一,遍历完毕即得到最终段数。

#include<iostream> 

using namespace std;

int a[1010];

int main()
{
    int n;
    cin>>n;
    int num=1;
    for(int i=0;i<n;i++){cin>>a[i];}
    for(int i=1;i<n;i++)
    {
    	if(a[i]!=a[i-1]){
    		num++;
		}}
        cout<<num<<endl;
    }

T2
给定一个棋盘,一个格子一种颜色。当一行或一列上有连续三个或者更多相同颜色的棋子时,颜色消除(一个棋子可以在某一行和某一列同时被消除),输出消除后的棋盘。
消除:对于棋盘任何一行或一列,我们记录在该行或该列中连续的颜色相同的棋子数量。若数量不小于3,则对这些棋子进行颜色消除。为避免行的消除对列的影响或列的消除对行的影响,我们将行与列的消除分开进行,只要消除过一次,则颜色就被消除。

#include<iostream> 

using namespace std;

int a[35][35];
int b[35][35];

int main()
{
    int n,m;
    cin>>n>>m;
    int sum=1;
    for(int i=0;i<n;i++){
    	for(int j=0;j<m;j++){
    		cin>>a[i][j];
    		b[j][i]=a[i][j];
		}
	}
    for(int i=0;i<n;i++){
    	for(int j=1;j<m;j++){
    		if(a[i][j]==a[i][j-1]){
    			sum++;
    			if(j==m-1){
    				if(sum>2){
    					for(int k=0;k<sum;k++){a[i][j-k]=0;}}
				sum=1;}
			}
			else{
				if(sum>2){
					for(int k=1;k<=sum;k++){
						a[i][j-k]=0;}}
			sum=1;}
		}
	}
	for(int i=0;i<m;i++){
    	for(int j=1;j<n;j++){
    		if(b[i][j]==b[i][j-1]){
    			sum++;
    			if(j==n-1){
    				if(sum>2){
    					for(int k=0;k<sum;k++){b[i][j-k]=0;}}
				sum=1;}
			}
			else{
				if(sum>2){
					for(int k=1;k<=sum;k++){
						b[i][j-k]=0;}}
			sum=1;}
		}
	}
	for(int i=0;i<n;i++){
    	for(int j=0;j<m;j++){
    		if(a[i][j]==0||b[j][i]==0){cout<<"0";}
			else{cout<<a[i][j];}
			if(j<m-1){cout<<" ";}}
		if(i<n-1) cout<<endl;
	}
    }

T4
给定一个字符串,计算字符串中delicious子串的数量。delicious子串定义:当且仅当每一个字符都属于一个大于1的回文串。
根据题意,delicious串分为两种:回文串和由回文串连接构成的字符串。如果按照这个思路固然可以算出所有delicious串,但在字符串长度极大时情况无疑会十分复杂。我们不妨反过来思考:什么样的子串不是delicious串?经过分析:子串的第一个元素为一种,剩余元素为一种与子串最后一个元素为一种,剩余元素为一种的情况才不构成deliciou串。由此,我们可以找出1所有非delecious串,由总串数减去非delecious串数,我们就得到了所有delicious串数。

#include<iostream>
#include<string>
using namespace std;

int main()
{   int n;
    cin>>n;
    string s;
    cin>>s;
    long long int ans;
	ans=1ll*(n-1)*n/2;
	int p=0;
	int num=0;
	for(int i=1;i<n;i++){
	    if(s[i-1]!=s[i]){
		    ans=ans-(i-p);
		    p=i;}}
	p=0;
	for(int i=1;i<n;i++)
	if(s[i-1]!=s[i])
	{   p=i-1;
		while(s[i]==s[i+1]){
			i++;
		}
		ans=ans-(i-p);
		num++;
	}
	ans=ans+num;
	cout<<ans;
	return 0;
}

12周
A题
给出n个数,找出出现至少(n+1)/2次的数。
对于输入的序列我们先进行排序(保证相同的数位置相邻)。从第一个位置开始遍历,找出每一个数的数量,数量不小于(n+1)/2直接输出,反之继续查找。

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

int a[1000001]; 
int main(){
    int N;
    while(cin>>N){
    	for(int i=0;i<N;i++){
    		cin>>a[i];
		}
	sort(a,a+N);
	a[N]=-1;
	int sum=1;
	for(int i=0;i<N;i++){
		if(a[i]==a[i+1]){sum++;}
		else{
			if(sum>=(N+1)/2){ cout<<a[i]<<endl;break;}
			sum=1;}
	}}
    
    return 0;
}

B题
三维迷宫寻找路径,每次只能向上下左右前后移动,判断路径是否存在及走出迷宫消耗时间。
三维迷宫最短路径问题,与二维迷宫相似,从起点开始进行广度优先搜索。到达终点时的路径长度即为最小时间。

#include<iostream>
#include<queue>
using namespace std;

struct point
{
    int z,x,y;
};

int space[30][30][30]; 
point pre[30][30][30];
int dxyz[6][3]={{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
int main(){
    int L,R,C;
    char c;
    point s,e,q;
    while(cin>>L>>R>>C&&L!=0&&R!=0&&C!=0){
    	for(int i=0;i<L;i++){
    		for(int j=0;j<R;j++){
    			for(int k=0;k<C;k++){
    	            cin>>c;
					if(c=='#'){space[i][j][k]=1;}
					else if(c=='.'){space[i][j][k]=0;}
					else if(c=='S'){space[i][j][k]=0;s.z=i;s.x=j;s.y=k;}
					else if(c=='E'){space[i][j][k]=0;e.z=i;e.x=j;e.y=k;}}}}
	queue<point> Q;
	Q.push(s);
	space[s.z][s.x][s.y]=1;
	bool flag=false;				
	 while(!Q.empty()&&!flag)
    {   
        for(int i=0;i<6;i++)
        {
            q.x=Q.front().x+dxyz[i][1];
            q.y=Q.front().y+dxyz[i][2];
            q.z=Q.front().z+dxyz[i][0];
            if(q.x>=0&&q.x<R&&q.y>=0&&q.y<C&&q.z>=0&&q.z<L&&space[q.z][q.x][q.y]!=1)
            {
                Q.push(q);
                space[q.z][q.x][q.y]=1;
                pre[q.z][q.x][q.y]=Q.front();
                if(q.z==e.z&&q.x==e.x&&q.y==e.y)
                {
                	flag=true;
                    break;
                }}}
        Q.pop();
    }
    if(flag){
	int sum=0;
        while(q.z!=s.z||q.x!=s.x||q.y!=s.y)
        {
            int z=q.z,x=q.x,y=q.y; 
            q.z=pre[z][x][y].z;
            q.x=pre[z][x][y].x;
            q.y=pre[z][x][y].y;
            sum++;
        }
	cout<<"Escaped in "<<sum<<" minute(s)."<<endl;}
    else {cout<<"Trapped!"<<endl;}}
	return 0;}
    

C题
每个寝室里面有ai个人。从第i到第j个宿舍一共有sum(i,j)个人,找到sum(i1, j1) + … + sum(im,jm)的最大值。且m段都不能相交。
无论到哪一个宿舍,都会出现两种可能:一是与其他宿舍一起组成其中的一段,另一种是另起新的一段。我们取其中的最大值作为到达该宿舍的最大值。重复m次,对每个最大值进行遍历,我们就得到了m次加法中的最大值。

#include<iostream> 
#include<stdio.h>
#include<string.h>
#include<math.h>

using namespace std;

int a[1000010];
int dp[1000010];
int s[1000010];

int main()
{
    int m,n;
    while(cin>>m>>n)
    {   memset(dp,0,sizeof(dp));
        memset(s,0,sizeof(s));
        int sum=0;
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);}
        for(int i=1;i<=m;i++)
        {
                sum=-9999999;
                for(int j=i;j<=n;j++)
                {
                    dp[j]=max(dp[j-1]+a[j],s[j-1]+a[j]);
                    s[j-1]=sum;
                    sum=max(sum,dp[j]);
                }
        }
        cout<<sum<<endl;
    }
    return 0;
}
相关标签: 实验报告