题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6351

题意:输入T组测试,每组测试样例输入一个数n和交换次数k,输出k次交换后能得到的最大数和最小数。

思路:利用全排列进行暴力操作。首先利用全排列可以得到所有的情况,然后找到交换k次的情况所得到的数跟最大数和最小数比较,然后更新最大数和最小数。然后接下来主要就是怎样判断交换了多少次。这里我们用flag数组标记下标,再用vis数组来标记我们要查询的数是否已经被判断过,然后我们需要用一个while循环来判断跟它交换的数是否又跟其他的数进行了交换,这样我们就知道了一共有几个数进行了交换,也就知道了一共交换了多少次,同时不要忘记把这些数的vis标记为1,表示这些数已经被访问过了。

My  DaiMa:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define per(i,a,b) for(int i = a; i < b; i++)
using namespace std;
const int Max = 10000003;
typedef long long ll;
int a[15],flag[15],vis[15],len;//a数组存的是字符串中的每一位数,flag用来存下标,vis用来标记
ll k;//输入的交换次数
int Count()
{
    fill(vis,vis+len,0);
    int c = 0;
    //for( int i = 0; i < len; i++)
    per(i,0,len)
    {
        if(vis[i] == 0)
        {
            int t = 0;
            while(vis[i] == 0)
            {
                vis[i] = 1;//将访问过的数标记为1
                t++;//t代表跟第i个数交换有关的数一共有几个
                i = flag[i];//将下标指向跟它进行交换的数的下标,即判断跟它交换的数是否还与其他的数进行了交换
            }
            c += t-1;//用来记录交换次数
        }
        if(c > k) return 0;

    }
    return c;//返回交换次数
}
int main()
{
    int t;

    char s[15];
    scanf("%d",&t);
    while( t-- )
    {
        scanf("%s %d",s,&k);//用字符串来存输入的数
        len = strlen(s);
        ll n = 0,mx,mn;
        //for(int i = 0; i < len; i++)
        per(i,0,len)
        {
            a[i] = s[i]-'0';
            flag[i] = i;
            n = n*10+a[i];
        }
        mx = mn = n;
        do
        {
            if(a[flag[0]] != 0 && Count() != 0)//要找交换k次的情况并且全排列所组合的这个数不能是前导0
            {
                ll sum = 0;
                //for(int i = 0; i < len; i++)
                per(i,0,len)
                    sum = sum*10+a[flag[i]];
                mx = max(mx,sum);//更新最大数
                mn = min(mn,sum);//更新最小数
            }

        }while(next_permutation(flag,flag+len));//注意是下标全排列
        printf("%lld %lld\n",mn,mx);
    }
}