@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
这里是菜鸡荔枝 祝大家周末愉快&祝我生日快乐!