小菜鸡的破思路|数据结构与算法MOOC内排序Ⅱ

@TOC小菜鸡的破思路|数据结构与算法MOOC内排序Ⅱ作业

小菜鸡的破思路|数据结构与算法MOOC内排序Ⅱ

用CSDN写了这么久的作业…突发奇想记录一下自己的作业思路也可hhh

1:Freda的越野跑

原题:http://dsa.openjudge.cn/hw10/1/

描述
Freda报名参加了学校的越野跑。越野跑共有N人参加,在一条笔直的道路上进行。这N个人在起点处站成一列,相邻两个人之间保持一定的间距。比赛开始后,这N个人同时沿着道路向相同的方向跑去。换句话说,这N个人可以看作x轴上的N个点,在比赛开始后,它们同时向x轴正方向移动。
假设越野跑的距离足够远,这N个人的速度各不相同且保持匀速运动,那么会有多少对参赛者之间发生“赶超”的事件呢?

输入
第一行1个整数N。
第二行为N 个非负整数,按从前到后的顺序给出每个人的跑步速度。
对于50%的数据,2<=N<=1000。
对于100%的数据,2<=N<=100000。

输出
一个整数,表示有多少对参赛者之间发生赶超事件。

样例输入

5
1 3 10 8 5

样例输出

7

提示

我们把这5个人依次编号为A,B,C,D,E,速度分别为1,3,10,8,5。
在跑步过程中:
B,C,D,E均会超过A,因为他们的速度都比A快;
C,D,E都会超过B,因为他们的速度都比B快;
C,D,E之间不会发生赶超,因为速度快的起跑时就在前边。

思路
一开始在想peach,想用map/set,边输入数据边记录当前元素之前的所有数,然后输入的同时查找之前有多少个小于他,就是“正序对”,结果忘了如果排好序的话nlogn,加上for循环n^2logn,还不如直接两层for是n^2。

于是用了正统思路orz。

归并排序当中求逆序对,大体思路就是在二路归并的过程中,若第二个子串的当前元素s2大于第一个子串的当前元素s1,那么因为第一串中s1后面的元素已经经过归并,统统比s1小,且都出现在s2前面,故正序数要加上s1直到第一串的末位的所有元素的个数。
如果s1>=s2,那么不产生正序对,继续归并即可。这样归并排序做完,正序对数也就求出来了。

因为是借鉴的dalao的代码,所以就不放上来了orz
https://blog.csdn.net/qq_41565901/article/details/84937345
话说没经过授权可以放链接嘛orz
如果不可以的话侵权删(


2:The Peanuts

http://dsa.openjudge.cn/hw10/2/
懒得复制+翻译了
思路
暴力模拟即可。找到了大一上的写过的代码(以及找到了以前的一个错误hhhhhh
需要在判断步数k是否够用的前面,先判断是否是第一次入田,是的话更新nowj=maxj,因为入田前可以在道路上平移,不算|nowj-maxj|时间。
大一写的时候居然在进入摘果子的if判断之后再进行的判断第一次入田,更新nowj,当时居然过了…不可思议hhh
以及这里可以k预先-2,省出来入田再出田的时间,判断里也不用每次都再if(k>=step+maxi+2)里写那个2了(
反正大一上的程序,不论是定义变量还是函数的美观程度和bug错误率上都好差劲hhh

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int main(){
	int N,m,n,k,i,j,a[50][50],max=0,maxi=0,maxj=0,nowi=-1,nowj=0,sum=0;
	cin>>N;
	while(N--){
		memset(a,0,sizeof(a));
		cin>>m>>n>>k;
		//cout<<"k1="<<k<<endl;
		max=0;
		for(i=0;i<m;i++)
		for(j=0;j<n;j++)
		    cin>>a[i][j];
		while(k){
			max=0;
			for(i=0;i<m;i++){
				for(j=0;j<n;j++){
					if(max<a[i][j]){
						max=a[i][j];
						maxi=i;
						maxj=j;
					}
				}
			}//找到最大值所在行列 
			if(!max)break;
			if(sum==0){
				nowj=maxj;
				nowi=-1;
			}//如果是第一次摘 则从路走过去需要+1s 列无需变 
			if((k-abs(maxi-nowi)-abs(maxj-nowj)-maxi-2)>=0){//如果足够返回则去摘 
				//cout<<"maxi="<<maxi<<"maxj="<<maxj<<endl;
				k-=abs(maxi-nowi)+abs(maxj-nowj)+1;
				//cout<<"k="<<k<<endl;
				sum+=max;
				//cout<<"sum="<<sum<<endl;
				a[maxi][maxj]=0;
				max=0;
				nowi=maxi;
				nowj=maxj;//改变当前位置信息 
			}
			else break;
		}
		cout<<sum<<endl;
		sum=0;
	}
	return 0;
}

3:DNA排序

描述
现在有一些长度相等的DNA串(只由ACGT四个字母组成),请将它们按照逆序对的数量多少排序。逆序对指的是字符串A中的两个字符A[i]、A[j],具有i < j 且 A[i] > A[j] 的性质。如字符串”ATCG“中,T和C是一个逆序对,T和G是另一个逆序对,这个字符串的逆序对数为2。

输入
第1行:两个整数n和m,n(0<n<=50)表示字符串长度,m(0<m<=100)表示字符串数量

第2至m+1行:每行是一个长度为n的字符串

输出
按逆序对数从少到多输出字符串,逆序对数一样多的字符串按照输入的顺序输出。

样例输入

10 6
AACATGAAGG
TTTTGGCCAA
TTTGGCCAAA
GATCAGATTT
CCCGGGGGGA
ATCGATGCAT

样例输出

CCCGGGGGGA
AACATGAAGG
GATCAGATTT
ATCGATGCAT
TTTTGGCCAA
TTTGGCCAAA

第一次RE惹,数组的缘故orz
大体上还是与第一题同样的思路,求出来每个的逆序数,然后冒泡/sort就行,以一个struct一起排序比较好,当然也可以冒泡的时候带着角标一起交换。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int v[50][100];
int tmpv[50][100];
int re[100]={0};//记录逆序数
struct DNA{
	char dna[55];
	int s;
}d[100];
bool cmp(DNA d1,DNA d2){
	return d1.s<d2.s;
}
void merge(int pos,int l,int mid,int r);
void mergesort(int pos,int l,int r){
	if(l==r)return;
	int mid=l+(r-l)/2;
	mergesort(pos,l,mid);
	mergesort(pos,mid+1,r);
	merge(pos,l,mid,r);
}
void merge(int pos,int l,int mid,int r){
	for(int i=l;i<=r;++i){
		tmpv[pos][i]=v[pos][i];
	}
	int index1=l,index2=mid+1,i=l;
	while( index1<=mid && index2<=r ){
		if(tmpv[pos][index1]<=tmpv[pos][index2]){
			v[pos][i++]=tmpv[pos][index1++];
		}
		else{
			v[pos][i++]=tmpv[pos][index2++];
			re[pos]+=mid+1-index1;
			//从小到大归并,index1后面的都比index2大而先出现,都是逆序 
		}
	}
	while(index1<=mid){
		v[pos][i++]=tmpv[pos][index1++];
	} 
	while(index2<=r){
		v[pos][i++]=tmpv[pos][index2++];
	}
}
int main(){
	int n,m;
	int l,p[100];
	cin>>n>>m;
	for(int i=0;i<m;++i){
		p[i]=i;
		cin>>d[i].dna;
		l=strlen(d[i].dna);
		for(int j=0;j<l;++j){
			v[i][j]=(int)(d[i].dna[j]-'A');
		}
		mergesort(i,0,l-1);
	}
	for(int i=0;i<m;++i){
		d[i].s=re[i];
	}
	sort(d,d+m,cmp);
	for(int i=0;i<m;++i){
		cout<<d[i].dna<<endl;
	}
	return 0;
}

似乎也可以暴力两个for找逆序对不像第一个要求这么严格的时间复杂度hhh

忘了做书面作业了(惨
又熬夜了…明天还和室友约了自习…起不来怕不是打死我(x
这里是菜鸡荔枝 祝大家周末愉快&祝我生日快乐!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值