PTA写BUG日志——贪心篇(算法笔记上机实战)

贪心第一弹

B1023组最小个数
这题不难,属于基础题,第一次提交的时候忽略了一个小细节,就是判断有0之后需要定位第一个非零的数字并输出,代码中的这一行,需要注意的是,需要判断啊a[i]不为0,否则会超时以及输出错误(细心,细心,细心)

if(flag&&i&&a[i]){
//1023组个数最小
#include<bits/stdc++.h>
using namespace std;
int a[10];
bool flag=false;
int main(){
	int fir;//记录第一个非零的数字 
	for(int i=0;i<10;i++){
		scanf("%d",&a[i]);
		if(i==0&&a[i]){
			flag=true;//表示存在0 
		}
		if(flag&&i&&a[i]){
			fir=i;
			printf("%d",fir);
			a[i]--;
			flag=false;
		}
	}	

	//如果没有0存在的话
	for(int i=0;i<10;i++){
			while(a[i]){
				printf("%d",i);
				a[i]--;
			}
		}  
	
	return 0;
} 

贪心第二弹

A1070月饼

这边存在的问题是,3/5的正确率:

//甲级1070
#include<bits/stdc++.h>
using namespace std;
//计算最大利润
int n,d;
struct mooncake{
	int ton;
	double price;
}a[1100];
bool cmp(mooncake a,mooncake b){
	return (a.ton/a.price)<(b.ton/b.price);
}
int main(){
	scanf("%d%d",&n,&d);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i].ton);
	}
	for(int i=0;i<n;i++){
		scanf("%lf",&a[i].price);
	}
	double sum=0;
	sort(a,a+n,cmp); 
/*
	for(int i=0;i<n;i++){
		printf("%f",a[i].price );
		printf("\n");
	}
*/
	for(int i=0;i<n;i++){
		if(a[i].ton<=d){
			d-=a[i].ton;
			sum+=a[i].price;
		}else{
			sum+=a[i].price*d/a[i].ton;
			d=0;
		}
		if(d==0){
			printf("%.2f",sum);
			return 0;
		}
	}
	return 0;
} 

然后参考了AC代码发现两个错:
首先是输入的demand可以是浮点数(玛德,题目明明说是整数),然后输入的月饼数量也可以为浮点数(好的,是我没有生活经验👌)
最后……忘记考虑供小于求的问题了,也即是d>0俺没有输出(罪过呀,说好的细心呢?)

//甲级1070
#include<bits/stdc++.h>
using namespace std;
//计算最大利润
int n;double d;
struct mooncake{
	double ton;//注意此处是浮点数 
	double price;
	double per; 
}a[1100];
bool cmp(mooncake a,mooncake b){
	return a.per>b.per;
	//else return a.ton/a.price<b.ton/b.price;
}
int main(){
	scanf("%d%lf",&n,&d);//注意此处是浮点数 
	for(int i=0;i<n;i++){
		scanf("%lf",&a[i].ton);
	}
	for(int i=0;i<n;i++){
		scanf("%lf",&a[i].price);
		a[i].per=a[i].price/a[i].ton;
	}
	double sum=0;
	sort(a,a+n,cmp); 
	for(int i=0;i<n;i++){
		if(a[i].ton<=d){
			d-=a[i].ton;
			sum+=a[i].per*a[i].ton; 
		}else{
			sum+=a[i].per*d;
			printf("%.2f",sum);
			return 0;
			d=0;
		}
		if(d==0.0){
			printf("%.2f",sum);
			return 0;
		}
	}
	//会有情况是供小于求 
	printf("%.2f",sum);
	return 0;
} 

贪心第三弹

A1033 To Fill or Not to Fill
这题……记得寒假的时候就没有做的出来,1\7的通过率(还是乱蒙的那种~)

//1033
#include<bits/stdc++.h>
using namespace std;
//最便宜的价格或者是能够行驶的最长距离
struct Station{
	double price;
	double distance;
}a[600]; 
double C_max,D,D_avg;
int n;

bool cmp(Station a,Station b){
	if(a.distance!=b.distance )return a.distance<b.distance;
	else return a.price<b.price;
} 
int main(){
	scanf("%lf %lf %lf %d",&C_max,&D,&D_avg,&n);
	for(int i=0;i<n;i++){
		scanf("%lf%lf",&a[i].price,&a[i].distance );
	}
	double D_max=C_max*D_avg;//加满油之后行驶的最大距离 
	double nd=0;//当前行驶距离 
	double cost=0;//当前耗费 
	sort(a,a+n,cmp);
	if(a[0].distance!=0){//如果起点没有补给 
			printf("The maximum travel distance = 0");
			return 0;
	}
	
	
	//操作 
	double  ndmax=0;//当前能达到的最远的距离 
	int i;
	int pre=0;int next;
	for( i=0;i<n;i++){
		if(i&&a[i].distance==a[i-1].distance) {
			i++;
		}
		cost+=a[i].price*C_max;//加满
		nd=a[i].distance;//更新距离 
		ndmax=nd+D_max;//从当前加油站可以到达的最大距离 
//		printf("ndmax:%lf cost:%lf nd=%.2f\n",ndmax,cost,nd);
		next=i+1;
		while(a[next].distance<=ndmax){
			if(a[next].distance==a[i].distance){
				next++;
				continue;
			}else{
				if(a[next].distance<=ndmax){//如果在距离范围内 
					if(a[next].price<=a[i].price){//如果价格更低的话 
						cost-=(a[next].distance-a[i].distance)/D_avg*a[i].price;
						i=next-1;//这就是下一个i的位置 
						break;
					}
					//问题是:如果价格更高要不要考虑 
				}
			}
		}
	}
//	printf("debug:cost =%.2f distance=%.2f\n",cost,ndmax);
	if(ndmax>=D){
			cost-=(ndmax-D)*a[i].price;
			printf("%.2f",cost);
	} 
	else
	printf("The maximum travel distance = %.2f",ndmax);
	return 0;
}

参照《算法笔记》的解法,突破口如下(本身不难,但是我一直没想到车本身多余油量的问题~)

  • 当前的以及下一个车站:如果下一个车站比当前费用小(下一个必选);如果下一个费用大则继续遍历直到找到能够到的范围内价格最小的那个
  • 存贮当前车的油量为nc,若是下一个费用小,则当前车站加的油只需要刚好能抵达下一站就好,若下一站费用大,则当前这站务必加满
    代码如下:
//1033A
#include<bits/stdc++.h>
using namespace std;
//C_max:最大容积,D:总距离,D_avg:一升油可以跑的公里数,N:总计多少加油站
double C_max,D,D_avg;
int N;
//加油站信息
struct Station{
	double d;
	double p;
}a[1000];
bool cmp(Station a ,Station b ){
	if(a.d!=b.d){
		return a.d<b.d;
	}else{
		return a.p<b.p;
	}
} 
int main(){
	scanf("%lf%lf%lf%d",&C_max,&D,&D_avg,&N);
	for(int i=0;i<N;i++){
		scanf("%lf%lf",&a[i].p,&a[i].d );
	}
	a[N].p=0;
	a[N].d=D;
	sort(a,a+N,cmp);
	//输入处理完毕

	double cost=0,nd=0;//当前能抵达的最远距离、开销 
	//情况一:出师未捷身先死 
	if(a[0].d>0){
		printf("The maximum travel distance = 0.00");
		return 0;
	} 
	//情况二:行驶 
	int i,j; 
	int next;
	double nc=0;//当前油量 
	for(i=0;i<N;){
		//i是当前停车站
		next=-1; 
		//next是下一个停车站
		for(int j=i+1;j<=N&&a[j].d<=a[i].d+C_max*D_avg;j++){
			if(a[j].p<=a[i].p){
				next=j;
				break;
			}else{
				if(next<0)next=j;
				else if(a[next].p>a[j].p)next=j;
			}
		} 
		if(next<0)break;//满油状况下没有找到车站
		//若找到下一站,则计算转移花费
		double need=(a[next].d-a[i].d )/D_avg;//需要的油量
		if(a[i].p>a[next].p){
			if(nc<need){
				cost+=(need-nc)*a[i].p;
				nc=0;
			} else{
				nc-=need;
			}
		} else{//若下一个费用大,则在当前加油站加满 
			cost+=(C_max-nc)*a[i].p;
			nc=C_max-need;
		}
			i=next; 
	} 
	if(i==N){
		printf("%.2f",cost);
	}else{
		printf("The maximum travel distance = %.2f",a[i].d+C_max*D_avg);
	}
	
	return 0;
} 

贪心第四弹

A1037 Magic Coupon
这题……与其说是贪心,感觉就是简单的排序昂~难过的时候可以刷刷的水题

//1037
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=100010;
long long ans;
long long a[maxn];
long long b[maxn];
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%lld",&a[i]);
	}
	scanf("%d",&m);
	for(int i=0;i<m;i++){
		scanf("%lld",&b[i]);
	}
	sort(a,a+n);
	sort(b,b+m);
	//先计算正数 
	int i=n-1;
	int j=m-1;
	while(i>=0&&j>=0){
		if(a[i]<0||b[j]<0)break;
		ans+=a[i]*b[j];
		i--;
		j--;
	}
	i=0;j=0;
	while(i<n&&j<m){
		if(a[i]>0||b[j]>0)break;
		ans+=a[i]*b[j];
		i++;
		j++;
	}
	printf("%d",ans);
	return 0;
} 

贪心第五弹

A1067 Sort with swap(0,*)
好难呀,不过输出N-1可以蒙对2/5的样例别问俺是咋知道的

4/6版本:未解决的问题——超时
思路还是蛮淳朴的,暴力试了一下就是这个思路:

  • 每次移动0和对应下标的数字
  • 如果0在本位,则移动0和随机一个不在本位的数字

接下来需要解决超时的问题

//A1067
#include<bits/stdc++.h>
using namespace std;
//只能移动0,请问需要至少移动多少次 
/*
思路:
每次移动0和对应下标的数字
如果0在本位,则移动0和随机一个不在本位的数字 
*/ 
int n;
int c=0;
int num[200000]; 
int ans=0;
//
void debug(){
	printf("排序:");
	for(int i=0;i<n;i++){
		printf("%d ",num[i]);
	}
	printf("\n");
} 
int main(){
	scanf("%d",&n);
	int pos;
	for(int i=0;i<n;i++){
		scanf("%d",&num[i]);
		if(num[i]==0)pos=i;//pos储存当前0的位置 
		if(num[i]!=i)c++;
	}
	bool flag=true;
	while(flag){
		//每次归位.n--
		//debug();
		if(pos==0){
			//如果0在本位,随机找一个不在本位的数字交换
			int i;
			for( i=1;i<n;i++){
				if(num[i]!=i){
					swap(num[i],num[0]);
					pos=i;
					ans++;
					break;
				}
			} 
			if(i==n)flag=false;
		} else{
			//如果0不在本位,找到0位置应该对应的数字并交换位置 
			for(int i=0;i<n;i++) {
				if(num[i]==pos){
					swap(num[i],num[pos]); 
					pos=i; 
					c--;
					ans++;
					break;
				} 
			}
		}
		
	}
	printf("%d",ans);
	return 0;
} 

AC代码:解决超时问题的map神器

解决时间复杂度的问题,我用了map来储存数组,具体思路是利用map构建一个错误的映射,每当swap得到一个正确的排序时候,从map映射中删除对应的错误映射
这种方法的优点是可以同时解决时间和空间复杂度的问题当然,前提是对map运用要熟悉
也算是一个小小的复习了,自己没百度独立写的感觉还是很不错哒~~

#include<bits/stdc++.h>
using namespace std;
const int maxn=100100;
int num[maxn];
int n;
int ans=0;
int pos;
map<int,int>wrong;//存储错误的位置信息 
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&num[i]);
		if(num[i]==0)pos=i;
		if(num[i]!=i){
			wrong[num[i]]=i;
			//wrong的索引是数字,得到的返回值是错误的位置 
		}	
	}
	map<int,int>::iterator it; 
	int temp;
	while(wrong.size()!=0){
	//	printf("worong:%d   pos:%d\n",wrong.size(),pos);
		it=wrong.begin();
		if(pos==0){
			//如果0在本位,则随机选择错误的数字交换位置
			if(it->first==0&&it->second==0){
				if(wrong.size()==1)
					break;
				else{
					it++;
				}
			}
			pos=it->second;
			wrong[it->first]=0;
			wrong[0]=pos;
			ans++;
		}else{
			//如果0不在本位 
			int a=wrong[0];//位置0对应的数字应该是a
			wrong[0]=wrong[a];//0与a交换位置
			pos=wrong[0]; 
		//	printf("a:%d\n",a);
			wrong.erase(a); //a归位,删除 
			ans++;
		}
	}
	printf("%d",ans);
	return 0;
} 

贪心第六弹

A1048 Recover the Smallest Number

4/7的正确率:BUG在于没有考虑全0的问题

//A1038
#include<bits/stdc++.h>
using namespace std;
const int maxn=10110;
string a[maxn];
int n;
bool cmp(string a,string b){
	//321 32
	return a+b<b+a; 
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	sort(a,a+n,cmp);
	bool flag=false; 
	for(int i=0;i<n;i++){
		if(flag){
			cout<<a[i];
			continue;
		}
		for(int j=0;j<a[i].length();j++){
			if(a[i][j]=='0')continue;
			else{
				flag=true;
				cout<<a[i][j];
			}
		}
	}

	return 0;
} 

这一题的主要问题是全0的情况下需要输出0,
然而后来又粗心啦,flag立下之后之后出现的0不需要跳过(555)
AC不易嗷

//A1038
#include<bits/stdc++.h>
using namespace std;
const int maxn=10110;
string a[maxn];
int n;
bool cmp(const string &a,string &b){
	//321 32
	return a+b<b+a; 
}
bool flag;
void print(string a){
	if(flag){
		for(int i=0;i<a.length();i++){
			cout<<a[i];
		}
	}else{
		for(int i=0;i<a.length();i++){
			if(!flag&&a[i]=='0')continue;
			else{
				flag=true;
				cout<<a[i];
			}
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n,cmp);
	flag=false;
	for(int i=0;i<n;i++){
		/*if(flag)cout<<a[i];
		else{
			for(int j=0;j<a[i].length();j++){
				if(a[i][j]=='0')continue;
				else{
					flag=true;
					cout<<a[i][j];
				}
			}
		}*/
		print(a[i]);	
	}
	if(!flag)printf("0");
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值