BFS预处理 hihoCoder1251 Today Is a Rainy Day

传送门:点击打开链接

题意:给你两串序列,长度最长为110,只由1~6组成。现在要把S2串变成S1串。有两种操作,每种操作执行一次代价都是1

操作1,把某一个数字变成另一个数字

操作2,把某一种数字变成另一个数字

求最小代价


思路:当时现场赛的时候确实很难想到,以为是一个dp,结果后来讲解的时候,出题人说就是一个BFS,至少BFS是一个非常熟悉的算法啊,当时没做出来有点小遗憾。

首先去分析操作1和操作2,可以发现,操作2肯定是最后才使用的。操作1先使用。那么我们就能想到,操作1一共会有哪些情况,可以发现操作1最多只有6^6种情况,就是一个数字变成其他的什么数字的投影的枚举,然后发现6^6才4w多,状态数还是很小的。再然后我们就能想到,{1,2,3,4,5,6}这种投影的代价当然是0,因为不动就可以了,那么怎么求其他投影的代价呢?问题就卡在了这一步,这里其实要用BFS来预处理。

我刚开始其实一直在想,为什么不能直接统计某一位上的数字不等于某一位的位置时就多一个代价呢,后来我发现这样想是不对的。比如{2,1,3,4,5,6}如果只是数位置的话,需要2点代价。但实际上,1和2是做不到2点代价交换的,不信可以自己手动模拟一下→_→

如果能想到这一步,那么后面的思路就会非常清晰了,就是一个枚举而已了。

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 5e4 + 5;
const int RB = 46656;
const int INF = 0x3f3f3f3f;

char S1[200], S2[200];
int dp[MX], G[10][10], cnt[10];

int idx(int c[]) {
    int ret = 0;
    for(int i = 0; i < 6; i++) {
        ret = ret * 6 + c[i];
    }
    return ret;
}

void ridx(int s, int c[]) {
    for(int i = 5; i >= 0; i--) {
        c[i] = s % 6;
        s /= 6;
    }
}

void presolve() {
    queue<int>Q;
    memset(dp, INF, sizeof(dp));
    int c[] = {0, 1, 2, 3, 4, 5}, id = idx(c);
    dp[id] = 0; Q.push(id);

    while(!Q.empty()) {
        int f = Q.front(), c[10], d[10];
        Q.pop();

        ridx(f, c);
        for(int i = 0; i < 6; i++) {
            for(int j = 0; j < 6; j++) {
                memcpy(d, c, sizeof(c));
                for(int k = 0; k < 6; k++) {
                    if(c[k] == i) d[k] = j;
                }
                id = idx(d);
                if(dp[id] == INF) {
                    dp[id] = dp[f] + 1;
                    Q.push(id);
                }
            }
        }
    }
}

int main() {
    //FIN;
    presolve();
    while(~scanf("%s%s", S1, S2)) {
        memset(G, 0, sizeof(G));
        memset(cnt, 0, sizeof(cnt));
        int l = strlen(S1);
        for(int i = 0; i < l; i++) {
            int u = S2[i] - '1', v = S1[i] - '1';
            G[u][v]++;
            cnt[u]++;
        }

        int ans = INF, c[10];
        for(int s = 0; s < RB; s++) {
            ridx(s, c);
            int sum = dp[s];
            for(int i = 0; i < 6; i++) {
                sum += cnt[i] - G[i][c[i]];
            }
            ans = min(ans, sum);
        }
        printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(BFS预处理 hihoCoder1251 Today Is a Rainy Day)