UVa 10716 - Evil Straw Warts Live

【链接】

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=113&page=show_problem&problem=1657


【原题】


A palindrome is a string of symbols that is equal to itself when reversed. Given an input string, not necessarily a palindrome, compute the number of swaps necessary to transform the string into a palindrome. By swap we mean reversing the order of two adjacent symbols. For example, the string "mamad" may be transformed into the palindrome "madam" with 3 swaps:

  • swap "ad" to yield "mamda"
  • swap "md" to yield "madma"
  • swap "ma" to yield "madam"

The first line of input gives n, the number of test cases. For each test case, one line of input follows, containing a string of up to 100 lowercase letters. Output consists of one line per test case. This line will contain the number of swaps, or "Impossible" if it is not possible to transform the input to a palindrome.

【Sample Input】

3
mamad
asflkj
aabb

【Output for Sample Input】

3
Impossible
2


【题目大意】

给一个单词,为了让它变成一个回文串,允许相邻的两个数交换。求最少的交换次数,使得单词变成一个回文串。


【分析与总结】

首先是要判断这个单词能否构成回文串, 只需要查看每个单词出现的次数,如果出现次数为奇数的个数大于1的话,就不能构成回文串。

然后,为了让移动最少,应该先让单词的外面两端变成相同的字母,设两端的位置为left, right, 那么初始时在最外面的两端就是left=0, right=len-1,让这两个位置变成相同的字母,然后在依次向内,++left, --right;

接着就是要选择让哪个字母成为这两端上相同的字母,这个选择就涉及到贪心的思想。

为了让移动次数最少,那么必须要让每次字母移动到left和right的移动次数最少, 所以 ,需要找到相同的字母第一次出现,最后一次出现,它们的位置距离left和right的总距离最少的那个字母, 让这个字母第一次出现的移动到left,最后一次出现的移动到right。 

如此循环,当left==right时结束,就得到最少的移动次数。


【代码】

/*
 *  UVa:10716 - Evil Straw Warts Live 
 *  Time: 0.012s  
 *  Author: D_Double
 *
 */
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 8005

using namespace std;

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

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

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

int solve(){
    int len=strlen(str), cnt=0;
    int left=0, right=len-1;
    while(left<right){
        // 先找到距离两端最短的那个字母
        int minFirst=left, minLast=right, maxDist=MAXN+100;
        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<maxDist){
                minFirst=i, minLast=lastOccur;
                maxDist=i-left+right-lastOccur;
            }
        }
        // 找到之后开始交换移动
        for(int i=minFirst; i>left; --i){
            swap(str[i], str[i-1]); 
            ++cnt;
        }
        for(int i=minLast; i<right; ++i){
            swap(str[i], str[i+1]);
            ++cnt;
        }
        // 向内收缩
        ++left; 
        --right;
    }
    return cnt;
}



int main(){

    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str);
        if(isPossible()){
            int ans=solve();
            printf("%d\n", ans);
        }
        else
            puts("Impossible");
    }
    return 0;
}



——  生命的意义,在于赋予它意义。

          
     原创 http://blog.csdn.net/shuangde800 , By   D_Double  (转载请标明)




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值