程序设计思维与实践week11作业 必做11-1~4,选做11-1~2

必做:

11-1

题目:
买房子

思路
在一个for循环内循环20次,如果可以买下将flag置为1,同时将年数记录在m中。最后根据flag的值输出对应结果。注意增长率处理成浮点型。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
	int N;
	float K;
	float hp=200;
	int flag=0,m=0;
	
	scanf("%d%f",&N,&K);
	K=K/100.0;
	for(int i=1;i<=20;i++){
	     if(i*N>=hp){
	     	flag=1;
			m=i;
			break;
		 }
		 else{
            hp=hp*(1+K);
		 }	
	}
	if(flag==1)cout<<m<<endl;
	else cout<<"Impossible"<<endl;
	
} 

11-2

题目:
蒜头君队列

思路
用二维矩阵**s[22][22]**存储方阵的原始信息 ,t[22][22] 记录最后的目标结果。
题目中的四中旋转实质上是对矩阵进行不同角度的旋转位置映射。
不旋转:s[i][j] == t[i][j];
顺时针旋转 90° :s[i][j] == t[j][-i+n-1];
顺时针旋转 180°:s[i][j] == t[-i+n-1][-j+n-1];
顺时针旋转 270° :s[i][j] == t[-j+n-1][i];
对于每种操作的判断,只要有一个位置映射不相等则操作失败;
在solve()函数中封装对四种操作的判断;

ps:四种方式的旋转怎么更好地额封装呢?虽然感觉只是改个判断条件复制一下就好了,但是代码看着好长。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int n;
int s[22][22];
int t[22][22];

void input(){
	int tmp;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	  	 scanf("%d",&tmp);
	  	 s[i][j]=tmp;
	  }
    for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	  	 scanf("%d",&tmp);
	  	 t[i][j]=tmp;
	  }
}

int zero(){
	int flag=1;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	  	  //cout<<s[i][j]<<' '<<t[i][j]<<endl;
	      if(s[i][j] != t[i][j]){
	          flag=0;
			  break;
		  }
	  }
	if(flag==0)return 0;
	else return 1;
}



int one(){
	int flag=1;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	      if(s[i][j] != t[j][-i+n-1]){
	          flag=0;
			  break;
		  }
	  }
	if(flag==0)return 0;
	else return 1;
}
int two(){
	int flag=1;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	      if(s[i][j] != t[-i+n-1][-j+n-1]){
	          flag=0;
			  break;
	     }
     }
	if(flag==0)return 0;
	else return 1;
}
int three(){
	int flag=1;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++){
	      if(s[i][j] != t[-j+n-1][i]){
	          flag=0;
			  break;
	      }
     }
	if(flag==0)return 0;
	else return 1;
}

void solve(){
	if(zero())cout<<0<<endl;
	else if(one())cout<<1<<endl;
	else if(two())cout<<2<<endl;
	else if(three())cout<<3<<endl;
	else cout<<-1<<endl;
}

int main(){
	scanf("%d",&n);
	input();
	
	//cout<<zero()<<endl;
	
	solve();
	return 0;
}

11-3

题目:
简单密码
思路
用getline(cin,mi)输入数据对包含空格是可取的。
其次,可以定义常量字符串来标记26字母;
对于输入的每一个字符,如果是字母,则通过ming += table.at(c-65) ,利用ASCLL码定位字符,然后将对应的字符加入答案中,空格字符直接加入,最后输出ming即为翻译所得的明文。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<cstring> 
#include<algorithm>
using namespace std;
string  mi;
string  ming;
string table ="VWXYZABCDEFGHIJKLMNOPQRSTU";
int main(){
    getline(cin,mi);
	for(int i=0;i<mi.length();i++){
    	char c=mi.at(i);
		if(c>=65 && c<=90){
			ming += table.at(c-65);
		}
		else ming += c;
	}
	cout<<ming<<endl;
	return 0;
}

11-4

题目:
吃寿司
思路
我们首先需要找到数组中每一段连续数字的长度。
在遍历数组的过程中利用代表元的思想,k为目前遍历到的代表元,如果遍历到的元素与k相等,那么当前的num加一,否则更换代表元,num跳到下一个位置。
因为需要找到连续两断,则通过在num中一次遍历求相邻两个元素最小值得最大值得方法得到最后答案,需要记住最后答案乘2。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<cstring> 
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int num[maxn];
int n;
int main(){
	scanf("%d",&n);
	int index=0,m,k;//k是代表元; 
	for(int i=0; i<n; i++){
	    scanf("%d",&m);
	    if(i==0){
	    	k=m;
	    	num[index]++;
		}
		else{
			if(m==k)num[index]++;
			else{
				index++;
				num[index]++;
				k=m;
			}
		}
	}
	int ans=0;
	for(int i=0; i<=index-1; i++)
		ans=max( 2*min(num[i],num[i+1]) , ans);  
	
	cout<<ans<<endl;
	return 0;
}

选做

11-1

题目:
一家银行计划安装一台用于提取现金的机器。
机器能够按要求的现金量发送适当的账单。
机器使用正好N种不同的面额钞票,例如D_k,k = 1,2,…,N,并且对于每种面额D_k,机器都有n_k张钞票。
例如,
N = 3,
n_1 = 10,D_1 = 100,
n_2 = 4,D_2 = 50,
n_3 = 5,D_3 = 10
表示机器有10张面额为100的钞票、4张面额为50的钞票、5张面额为10的钞票。
东东在写一个 ATM 的程序,可根据具体金额请求机器交付现金。
注意,这个程序计算程序得出的最大现金少于或等于可以根据设备的可用票据供应有效交付的现金。
题目链接

思路:
可以把题目转化为01背包问题。对于所需要的总面额,我们可以将其看做是01背包问题中的背包总容量。
先对每种面额进行二进制拆分,假如有5张10元的钞票,拆分结果应该为110,210, 2*10(2<4);这样的拆分可以表示5张10元钞票的任意一种组合;
然后对拆分后的钞票进行01背包问题求解:

//01背包; //对cnt个物品,
		for(int i=1;i<=cnt;i++)
			for(int j=t;j>=0;j--){
				if(j-v[i]>=0)//update
				  f[j]=max(f[j],f[j-v[i]]+v[i]);
			}

最后寻找f[i]的最大值;

代码:

/*
week11E 二进制拆分01背包 
*/
#include<iostream>
#include<algorithm>
#include<string.h> 
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1e6;
int n,t,ans;
int a[11],b[11];
int f[maxn],v[maxn];

void init(){
	memset(f,0,sizeof(f));
	memset(v,0,sizeof(v));
	ans=0;
}
 
int main(){ 
	while(scanf("%d",&t)!=EOF){
		scanf("%d",&n);
	    init();
		for(int i=1;i<=n;i++)
		    scanf("%d%d",&a[i],&b[i]);
		    
		//二进制拆分 
		int cnt=0;
		for(int i=1; i<=n; i++){//每一种分解二进制; 
			int tp=a[i]//数量;
			for(int k=1;k<=tp;k<<=1){
				cnt++;
				v[cnt]=k*b[i];
				tp = tp-k;
			}
			if(tp>0){//补齐; 
				cnt++;
				v[cnt]=tp*b[i];
			}
		}
		
		//01背包; //对cnt个物品,
		for(int i=1;i<=cnt;i++)
			for(int j=t;j>=0;j--){
				if(j-v[i]>=0)//update
				  f[j]=max(f[j],f[j-v[i]]+v[i]);
			}
			
		//最大值; 
		for(int i=1;i<=t;i++)
		    ans=max(ans,f[i]);
		cout<<ans<<endl;
	}
	return 0;
}

11-2

题目:
东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢

假设:
CD数量不超过20张
没有一张CD唱片超过 N 分钟
每张唱片只能听一次
唱片的播放长度为整数
N 也是整数

我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)
本题是 Special Judge
题目链接

思路:
这一题也为背包问题,我们将开车总时长当做背包的总容量:f[i][j]表示j容量下前i个物品的最优解,先用背包方法求解:

//01背包
		for(int i=1; i<=M; i++){
			for(int j=0; j<=N; j++){
				f[i][j] = f[i-1][j];//前i-1件物品;
				if(j >= t[i])					
					f[i][j] = max( f[i][j] , f[i-1][j-t[i]] + t[i] );
			}
		 }

然后根据f的值判断一个物品有没有被装入到背包中,这里我们可以用一个状态数组记录每个物品是否被装入背包,注意每次判断成功需要将b减去t[i]也就是得到上一个状态的背包容量;最后根据vis[i]状态数组输出被选择的物品。

// 找唱片
		int b = N;
		for(int i=M;i>=1;i--){
			if(f[i][b] > f[i-1][b]){//装入了i;
				vis[i] = 1;			
				b -= t[i];//局部;
			}
		 }

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int N,M;
int t[22];//时间 
int f[22][10005];
int vis[22];

void init(){//初始化
	memset(vis,0,sizeof(vis));
	memset(f,0,sizeof(f));
	memset(t,0,sizeof(t));
}

int main(){
	while(cin>>N>>M){
		init();
		for(int i=1;i<=M;i++)
		    cin>>t[i];
		//01背包
		for(int i=1; i<=M; i++){
			for(int j=0; j<=N; j++){
				f[i][j] = f[i-1][j];//前i-1件物品;
				if(j >= t[i])					
					f[i][j] = max( f[i][j] , f[i-1][j-t[i]] + t[i] );
			}
		 }
		 
		// 找唱片
		int b = N;
		for(int i=M;i>=1;i--){
			if(f[i][b] > f[i-1][b]){//装入了i;
				vis[i] = 1;			
				b -= t[i];//局部;
			}
		 }
		 //output
		 for(int i=1;i<=M;i++){
		 	if(vis[i]==1)//唱片选中
		 	cout<<t[i]<<" ";
		  }
		  cout<<"sum:"<<f[M][N]<<endl;
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值