程序设计week11 作业

本文精选了多项算法竞赛题目,包括房价预测与购房策略、矩阵旋转对比、凯撒密码解密、连续数字最大配对、ATM取款最优策略及唱片收集问题。深入解析了动态规划、数学模型、字符串处理、数据结构等核心算法,提供了详细的代码实现。

A-必做题11-1

蒜头君从现在开始工作,年薪 NN 万。他希望在蒜厂附近买一套 6060 平米的房子,现在价格是 200200 万。假设房子价格以每年百分之 KK 增长,并且蒜头君未来年薪不变,且不吃不喝,不用交税,每年所得 NN 万全都积攒起来,问第几年能够买下这套房子?(第一年年薪 NN 万,房价 200200 万)

输入格式
一行,包含两个正整数 N(10 \le N \le 50)N(10≤N≤50),K(1 \le K \le 20)K(1≤K≤20),中间用单个空格隔开。

输出格式
如果在第 2020 年或者之前就能买下这套房子,则输出一个整数 MM,表示最早需要在第 MM 年能买下;否则输出"Impossible"。

输出时每行末尾的多余空格,不影响答案正确性

样例
输入
50 10
输出
8

解题思路
房价为 200 * pow( 1+ K/100 , i-1 )
工资为 i * N

比较2个的大小即可

代码实现

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

float N;
float K;
int main()
{
	cin>>N>>K;
	float a;
	float b;
	int flag=0;
	float i;
	for(i=1;i<=20;i++)
	{
		a = i * N;
		b = 200 * pow((1+K/100),i-1);
		
		if(a>=b) {
			cout<<i<<endl;
			flag++;
			return 0;
		}
	}
	if(flag==0)
	{
		cout<<"Impossible"<<endl;
		return 0;
	}
	
	return 0;
}

B - 必做题 11-2

在这里插入图片描述

样例输入

4
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0

样例输出
1

解题思路
顺时针90度 ---- [ i , j ] ----> [ j , n+1-i]
顺时针180度 -------[ i , j ] -----> [ n+1-i , n+1-j ]
顺时针270度 ------- [ i , j] -------> [ n+1-j ,i]

把当前矩阵和目标矩阵进行比较就可以了

代码

#include<iostream>
using namespace std;

bool a[25][25];
bool b[25][25];
int n;

bool _1()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!=b[i][j]) return 0;
		}
	}
	return 1;
}
bool _2()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!=b[j][n+1-i]) return 0;
		}
	}
	return 1;
}
bool _3()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!=b[n+1-i][n+1-j]) return 0;
		}
	}
	return 1;
}
bool _4()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i][j]!=b[n+1-j][i]) return 0;
		}
	}
	return 1;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>b[i][j];
		}
	}
	if(_1()) {cout<<0<<endl;return 0;}
	if(_2()){cout<<1<<endl;return 0;}
	if(_3()){cout<<2<<endl;return 0;}
	if(_4()){cout<<3<<endl;return 0;}
	cout<<-1<<endl;
	return 0;
}

C - 必做题11-3

在这里插入图片描述

样例
NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX

IN WAR, EVENTS OF IMPORTANCE ARE THE RESULT OF TRIVIAL CAUSES

解题思路

把一行字符串全部读取到string里面,
用getline(cin,str) , 
可以连同空格一起读入,如果只是用cin的话,遇到空格和回车就会停止

用 str[i] = (str[i]-'A'+26-5)%26+'A' 
来将该字符退回到前5

代码

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


bool jud(int i)
{
	char c[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
	for(int j=0;j<26;j++)
	{
		if(c[j]==str[i]) return 0;
	}
	return 1;
}

int main()
{
	getline(cin,str);
	
	for(int i=0;i<str.size();i++)
	{
	
		if(jud(i)) continue;
		else
		{
			str[i] = (str[i]-'A'+26-5)%26+'A' ;
		
		}
	}
	cout<<str<<endl;
	return 0;
}

D - 必做题11-4

在这里插入图片描述

Examples
Input
7
2 2 2 1 1 2 2
Output
4
Input
6
1 2 1 2 1 2
Output
2
Input
9
2 2 1 1 1 2 2 2 2
Output
6

解题思路

1.想办法把一段相同的个数个记录下来,例如11112222,记为4 4
2.然后把能够拿走的个数给记录下来,例如 11122221111,很显然为 3 4 
3.比较2中所有记录的大小,取出最大的

代码实现

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1e5+10;
int a[N];
vector<int> b;
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	int sum1=0;
	int flag=a[0];
	a[n] = -1;
	for(int i=0;i<=n;i++)  //第一步
	{
		if(flag==a[i])
		{
			sum1++;
			flag=a[i];
		}
		else
		{
			b.push_back(sum1);
			sum1=1;
			flag = a[i];
		}
	}

    int ai=0;
	for(int i=0;i<b.size()-1;i++) //第二步 
	{
		if(b[i]>b[i+1])
		{
			a[ai++] = b[i+1];
		}
		else
		{
			a[ai++] = b[i];
		}
	}
	sort(a,a+ai);         //第三步
	cout<<a[ai-1]*2;
	return 0;
}

E - 选做题11-1 东东与 ATM ( 多重背包+二进制拆分 == 0 1 背包 )

在这里插入图片描述

Sample Input
735 3  4 125  6 5  3 350
633 4  500 30  6 100  1 5  0 1
735 0
0 3  10 100  10 50  10 10
Sample Output
735
630
0
0

在这里插入图片描述

解题思路

1.多重背包 (一开始我写多重背包的代码,但是超时了)

代码

#include<iostream>
using namespace std;
const int N=100005;
struct W{
	int _nk_ , _dk_ ;  //_dk_ -- 面额  _nk_ 数量 
};

W w[15];
int f[15][N];

int main()
{
	int cash,n,nk,dk;  //cash总量 n面额数量 nk是dk的数量 dk是面额 
	while(cin>>cash>>n){
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]._nk_>>w[i]._dk_;
//		cout<<w[i]._dk_<<" "<<w[i]._nk_<<endl;
	}
	//initial
	for(int i=0;i<=N;i++)
		f[0][i] = 0;
	
	//多重背包
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=cash;j++)
		{
			f[i][j] = f[i-1][j];
	//		cout<<"1.fij="<<f[i][j]<<endl;
			for(int k=1;k<=w[i]._nk_;k++)
			{
				if(j - k * w[i]._dk_ >= 0){
					f[i][j] = max(f[i][j] ,f[i-1][j-k*w[i]._dk_]+k*w[i]._dk_);	
			//		cout<<"2.f["<<i<<","<<j<<"]="<<f[i][j]<<endl;
				}
			}
		}
	}
	int m=f[n][cash];
	cout<<m<<endl;
	}
	return 0;
 } 
2.二进制拆分后 ,还要转换成 01背包进行求解,不然可能会超空间
3.二进制拆分的思路:
例子: 111111 拆成 1 + 10 + 100 + 1000 + 100000.......
如果不能刚好拆完,则最后剩下的那个数也算为拆分的一部分

为什么要二进制拆分?
通过二进制拆分,可以转换成01背包
例如 111 = 1 + 10 + 100  ,本来是要在 111里面进行一个for循环遍历的(多重背包)
但是如果把他拆分了,就可以转换成 01 ,选或者不选,如果1 10 100全部都选了,加起来就是111 ,相当于在多重背包里面把这种物体选完了。
多重背包的那部分复杂度降为了log
但是还是不行,因为如果 f【】【】是二维的,是会超空间的
所以要用一维数组实现

代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
int cash,n,nk,dk;  //cash总量 n面额数量 nk是dk的数量 dk是面额 
struct W{
	int _nk_ , _dk_ ;  //_dk_ -- 面额  _nk_ 数量 
};

W w[15];
int ww[N];
int index;
int f[N];

void acc()   //二进制拆分 
{
	index=0;
	for(int i=1 ; i<= n ;i++)  //第i种面额 
	{
		int c = w[i]._nk_;
		for(int j=1;j<= c ;j<<=1)
		{
			index++;
			ww[index] = j*w[i]._dk_; 
			c -= j;
		 } 
		 if(c > 0)
		 {
		 	index++;
		 	ww[index] = c*w[i]._dk_;
		 }
	}
}

void ini() //初始化
{
	memset(ww,0,sizeof(ww));
	for(int i=0;i<15;i++)
	{
		w[i]._dk_=0;
		w[i]._nk_=0;
	}
	
	memset(f,0,sizeof(f));
}

int main()
{
	
	while(cin>>cash>>n){
	ini();
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]._nk_>>w[i]._dk_;
	}

	acc();

	//01 背包 
	for(int i=1; i<=index; i++)
	{
		for(int j=cash;j>=ww[i];j--)
		{
		f[j] = max(f[j] ,f[j-ww[i]]+ww[i]);
		}
	}
	cout<<f[cash]<<endl;
	}
	return 0;
 } 

F - 选做题11-2 东东开车了

在这里插入图片描述

Sample Input
5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2
Sample Output
1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45

解题思路

01背包求解 (需要用到的是二维的数组)
倒推过程
详情看代码注释

代码

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

int N,M;
int m[25];
int f[25][10005];
int a[25];

void ini()   //初始化
{
	memset(a,0,sizeof(a));
	memset(f,0,sizeof(f));
	memset(m,0,sizeof(m));
}

int main()
{
	while(cin>>N>>M)
	{
		ini();
		for(int i=1;i<=M;i++)
		cin>>m[i];

		//01背包
		for(int i=1;i<=M;i++)
		{
			for(int j=0;j<=N;j++)
			{
				f[i][j] = f[i-1][j];
				if(j>=m[i])
				{					
					f[i][j] = max( f[i][j] , f[i-1][j-m[i]] + m[i] );

				}
			}
		 }
	
		
		//倒推
		int b = N;
		for(int i=M;i>=1;i--)
		{
			if(f[i][b]>f[i-1][b])   //如果(f[i][b]>f[i-1][b]) 
			{						//则代表该状态选择了a【i】
				a[i] = 1;			
				b -=m[i];
			}
		 }
		 
		 for(int i=1;i<=M;i++)
		 {
		 	if(a[i]==1)         //如果为1 ,则该唱片被选择
		 	{
		 		cout<<m[i]<<" ";
			 }
		  }
		  cout<<"sum:"<<f[M][N]<<endl;
		  
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值