zoukankan      html  css  js  c++  java
  • UVALive

    原题链接

    题意

    给两个等长的只含数字1,2,3,4,5,6的字符串s(|s|≤110),有两种操作:

    - 把一个位置的数字换成另一个数字,换成的数字也只能是1到6
    - 把这个字符串中相同的数字都换成另一种数字
    应用上面的两种操作把第二个字符串转换成第一个字符串至少需要多少次操作?

    分析
    首先尽可能多的进行第二次操作一定是最优的。
    对于第二种操作,我们可以预处理出来变换到每个状态的最短步数,也就是用bfs跑。以123456标记为初始状态state,然后每次选择一个要变换的数字以及变换成的数字。
    那么,如何求解从第二个字符串变到第一个字符串的最少步数呢?根据上面的状态定义,初始状态为123456(位置1对应数字1,位置2对应数字2....),那么每到一个新的状态nxt,先用数组存起来对应位置的change[],遍历s2,如果change[s2[j]]!=s1[j](change[s2[j]]表示s2[j]在nxt状态下变成了change[s2[j]]),则需要进行操作1,tmp++。
    那么遍历所有状态,ans=min(ans,tmp+step[nxt])

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    #include <queue>
    using namespace std;
    const int MAX_N = 1000000;
    int total = 0, step[MAX_N], res[MAX_N], pw10[8];
    queue<int> que;
    char s1[120], s2[120];
    void bfs() {
        pw10[0] = 1;
        for (int i = 1; i <= 7; ++i) { pw10[i] = 10 * pw10[i - 1]; }
        memset(step, -1, sizeof (step));
        int st = 123456;
        step[st] = total, res[total++] = st;
        que.push(st);
        while (!que.empty()) {
            int cur = que.front();
            que.pop();
            for (int i = 1; i <= 6; ++i) {
                for (int j = 1; j <= 6; ++j) {
                    if (i == j) continue;
                    int nxt = 0;
                    for (int k = 5; k >= 0; --k) {
                        int p = cur / pw10[k] % 10;
                        if (p == i) nxt = nxt * 10 + j;
                        else nxt = nxt * 10 + p;
                    }
                    if (step[nxt] != -1) continue;
                    step[nxt] = step[cur] + 1;
                    res[total++] = nxt;
                    que.push(nxt);
                }
            }
        }
    }
    int main() {
        bfs();
        while (~scanf("%s%s", s1, s2)) {
            int len = strlen(s1);
            int ans = len, change[10];
            for (int i = 0; i < total; ++i) {
                int cur = res[i], tmp = 0;
                for (int j = 5, k = 1; j >= 0; --j) {
                    change[k++] = cur / pw10[j] % 10;
                }
                for (int j = 0; j < len; ++j) {
                    int to = change[s2[j] - '0'];
                    if (to != s1[j] - '0') tmp++;
                }
                ans = min(ans, tmp + step[cur]);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    java 多线程
    构造N位格雷码(递归,面向对象)
    字典树trie
    快速排序
    C++ 链表
    15-谜问题(深拷贝、LC检索、面向对象编程)
    [编程题] 扫描透镜(本题还涉及如何从字符串中提取数字)
    python爬虫提取冰与火之歌五季的种子
    带有限期和效益的单位时间的作业排序贪心算法
    0/1背包问题与动态规划
  • 原文地址:https://www.cnblogs.com/fht-litost/p/7337111.html
Copyright © 2011-2022 走看看