码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 6351 Beautiful Now

时间:2020-05-08 13:09:47      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:需要   数字   can   实现   while   str   har   置换   不能   

http://acm.hdu.edu.cn/showproblem.php?pid=6351

题目

给一个数字n,可以执行k次交换,每次交换都选择数字中的2位,并且交换后不能出现前导0,问能得到的最小值和最大值是多少。

T<=100,n,k<=10^9

题解

方法一

把交换看为对换,枚举排列,然后分解置换,n元循环至少可以分成n-1个对换,而且是最小的分法。

考虑循环$(1\quad2\quad3\quad\cdots\quad n)=(1\quad2)(1\quad3)(1\quad4)\cdots(1\quad n)$

为了拆开循环,每拆一次,原来循环的元素最多减少一个,因此至少n-1个

又发现可以拆成n-1个对换,所以就可以直接判断能不能在k次以内交换实现

分解置换需要$\mathcal{O}(n)$

时间复杂度$\mathcal{O}(n!\times n)$,需要卡常数,有可能超时

方法二

从前往后依次决定,每次选择最小/最大的数和当前位置交换,并把这个位置指针往后移动一位。时间复杂度$\mathcal{O}(n!)$

还可以优化,如果最小/最大的数和当前位置相等,那么直接把这个位置指针往后移动一位。顺序枚举1~1000000000发现跑得很快

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char n[11]; int l;
char Ma[11],ma[11];
void dfs1(int k, int p) {
	if(k>0 && p<l) {
		char m;
		for(int i=p; i<l; i++) if(p || n[i]!=‘0‘) { m=n[i];}
		for(int i=p; i<l; i++) if((p || n[i]>‘0‘) && n[i]<m) { m=n[i];}
		if(m!=n[p]) {
			for(int i=p; i<l; i++) if(n[i]==m) {
				swap(n[i], n[p]);
				dfs1(k-1,p+1);
				swap(n[i], n[p]);
			}
		} else dfs1(k, p+1);
	} else {
		if(strcmp(n,ma)<0) {
			strcpy(ma,n);
		}
	}
}
void dfs2(int k, int p) {
	if(k>0 && p<l) {
		char m=n[p];
		for(int i=p; i<l; i++) if(n[i]>m) { m=n[i];}
		if(m!=n[p]) {
			for(int i=p; i<l; i++) if(n[i]==m) {
				swap(n[i], n[p]);
				dfs2(k-1,p+1);
				swap(n[i], n[p]);
			}
		} else dfs2(k, p+1);
	} else {
		if(strcmp(n,Ma)>0) {
			strcpy(Ma,n);
		}
	}
}
int main() {
	int T; scanf("%d", &T);
	while(0<T--) {
		int k; scanf("%s%d", n, &k);
		strcpy(Ma,n); strcpy(ma,n);
		l=strlen(n); if(k>l) k=l;
		dfs1(k,0); dfs2(k,0);
		printf("%s %s\n", ma, Ma);
	}
}

 

HDU 6351 Beautiful Now

标签:需要   数字   can   实现   while   str   har   置换   不能   

原文地址:https://www.cnblogs.com/sahdsg/p/12849703.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!