今天的比赛,因为时间问题,我就做了这一个题
题目描述
给你一个n位数,每次操作可以选该数任意的相邻两位进行交换,如果最多可以操作k次,那么最终可以得到的最小的数是什么
(n位且不能含前导零)?
输入
有多组测试数据,第一行为数据个数T(T<=10); 每组数据占一行,包含一个数(不超过1000位)和k(0<=k<=1000),中间用空格隔开;
输出
最终能得到的最小的数。
样例输入
2 321654987 1 321654987 2
样例输出
231654987 132654987 这个题没有什么算法,就是用俩嵌套for循环,然后要注意一下边界条件就能A,比赛的时候WA了好几次,要么是忘了memset,要么ct忘了重置为0,要么就是j写成i,总之非常egg pain,犯了好多低级错误,不在状态啊。 我解释一下我的代码和思路把。 我这个类似于贪心算法,就是每次都把整个数列扫描一遍,用num[0~9]标记出0~9这10个数第一次出现的位置,然后从0开始往9for循环,如果最小的数的位置与当前要确定的位置距离小于等于k,那么就可以把这个数组挨个往后挪,然后把那个小的数放到当前操作的位置,k-=操作的距离。 我的代码还有好多需要完善的地方,能降低复杂度,但是比赛的时候比较匆忙,没顾上考虑这么多,能a就行。下面是我比赛的源代码。其实现在看有好多能剪枝的地方,如果这个算法超时,再改(我当时是这样想的)。 #include <iostream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string> #include <string.h> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <stack> using namespace std; typedef long long LL; const int INF=0x7fffffff; const int MAX_N=1009; int T,k,ct; char A[MAX_N]; int num[10]; int main(){ cin>>T; while(T--){ memset(A,0,sizeof(A)); scanf("%s",A); scanf("%d",&k); int len=strlen(A); memset(num,-1,sizeof(num)); ct=0; for(int i=1;i<len;i++){ if(num[A[i]-‘0‘]==-1){//这里也可以降复杂度,因为只要算小于A[0]的就行 num[A[i]-‘0‘]=i; ct++; } if(ct==10)break; } for(int i=1;i<=9;i++){//这个地方可以把9改成A[0]-‘0‘ if(num[i]<=k&&num[i]!=-1&&i<A[0]-‘0‘){ char cur=A[num[i]]; for(int j=num[i];j>=1;j--){ A[j]=A[j-1]; } A[0]=cur; k-=num[i]; break; } } for(int i=1;i<len;i++){ if(k==0)break; memset(num,-1,sizeof(num)); ct=0; for(int j=i+1;j<len;j++){ if(num[A[j]-‘0‘]==-1){ num[A[j]-‘0‘]=j; ct++; } if(ct==10)break; } for(int j=0;j<=9;j++){ if(num[j]-i<=k&&num[j]!=-1&&j<A[i]-‘0‘){ char cur=A[num[j]]; for(int p=num[j];p>i;p--){ A[p]=A[p-1]; } A[i]=cur; k-=num[j]-i; break; } } } cout<<A<<endl; } return 0; }
时间: 2024-11-10 18:56:10