uva 10716 Evil Straw Warts Live

题意:求最少的步骤使得原串变为回文串,贪心的做法很容易想到:每次都找离两端距离和最近的一对字符,然后分别移到两端就行了

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 8005;

char str[MAXN];
int vis[MAXN];

void swap(int &a,int &b)
{
    int t = a;
    a = b;
    b = t;
}

bool isok()
{
    memset(vis,0,sizeof(vis));
    for (int i = 0; str[i]; i++)
        vis[str[i] - 'a']++;
    int sum = 0;
    for (int i = 0; i < 26; i++)
        if (vis[i] % 2)
        {
            sum++;
            if (sum > 1)
                return false;
        }
    return true;
}

int solve()
{
    int len = strlen(str),sum = 0;
    int left = 0,right = len - 1;
    while (left < right)
    {
        int first = left,last = right,Max = MAXN *2;
        memset(vis,0,sizeof(vis));
        for (int i = left; i < right; i++)
        {
            if (!vis[i])
            {
                vis[i] = true;
                int lastOccur = i,j;
                for (j = i + 1; j <= right; j++)
                    if (str[j] == str[i])
                    {
                        vis[j] = true;   // 中间的就更不可能是这个字符的最短了
                        lastOccur = j;
                    }

                if (i - left + right - lastOccur < Max)
                {
                    first = i,last = lastOccur;
                    Max = i - left + right - lastOccur;
                }
            }
        }

        for (int i = first; i > left; i--)
        {
            swap(str[i],str[i-1]);
            sum++;
        }
        for (int i = last; i < right; i++)
        {
            swap(str[i],str[i+1]);
            sum++;
        }
        left++,right--;
    }
    return sum;
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%s",str);
        if (isok())
            printf("%d\n",solve());
        else printf("Impossible\n");
    }
    return 0;
}



你可能感兴趣的:(uva 10716 Evil Straw Warts Live)