zoukankan      html  css  js  c++  java
  • hihocoder 1251 Today is a rainy day ( 15年北京 C、暴力 )

    题目链接

    题意 : 一串数字变成另一串数字,可以单个数字转变,或者一类数字转变,问最少操作次数

    分析 :

    15年北京赛区的银牌题

    首先有一个点需要想明白、或者猜得到

    即最优的做法肯定是先做完 2 操作最后用 1 操作

    2 操作单次可以改变的字符数远大于 1 操作 ( 当然这个不是证明上面的结论、只是给个灵感去猜

    具体操作就是 s2 => 通过 2 操作变成中间状态 => 通过 1 操作变成 s1

    对于 2 操作、与具体字符的数量无关、只和种类有关、即从一种数字变成另一种

    那么就是一种映射关系、那么我们可以使用一个六位的六进制数来表示不同的状态

    首先将字符集全部 -1 、即原来串是由 {1,2,3,4,5,6} 组成变成由 {0,1,2,3,4,5}组成 ( 方便进制转化 )

    那么这种映射关系是什么呢?如何表示的 2 操作呢?

    比如 012345 => 112345 表示将原来字符所有的 0 变成 1

            012345 => 112344 表示将原来字符串所有的 0 变成 1、所有的 5 变成 4

    所有对于所有的状态、可以使用 BFS 从初始状态 (012345)6 开始、将它到其他状态的花费求出来

    那么就可以统计出所有 2 操作能到达的状态的最小花费了、当然六进制的状态最后要用十进制存储才方便存储

    最后就是像刚刚说的那样子、先枚举中间状态(6^6个最多)、然后计算出从中间状态通过 1 操作到达目标状态的花费即可

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    
    #define scl(i) scanf("%lld", &i)
    #define scll(i, j) scanf("%lld %lld", &i, &j)
    #define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
    #define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)
    
    #define scs(i) scanf("%s", i)
    #define sci(i) scanf("%d", &i)
    #define scd(i) scanf("%lf", &i)
    #define scIl(i) scanf("%I64d", &i)
    #define scii(i, j) scanf("%d %d", &i, &j)
    #define scdd(i, j) scanf("%lf %lf", &i, &j)
    #define scIll(i, j) scanf("%I64d %I64d", &i, &j)
    #define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
    #define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
    #define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
    #define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
    #define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
    #define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)
    
    #define lson l, m, rt<<1
    #define rson m+1, r, rt<<1|1
    #define lowbit(i) (i & (-i))
    #define mem(i, j) memset(i, j, sizeof(i))
    
    #define fir first
    #define sec second
    #define VI vector<int>
    #define ins(i) insert(i)
    #define pb(i) push_back(i)
    #define pii pair<int, int>
    #define VL vector<long long>
    #define mk(i, j) make_pair(i, j)
    #define all(i) i.begin(), i.end()
    #define pll pair<long long, long long>
    
    #define _TIME 0
    #define _INPUT 0
    #define _OUTPUT 0
    clock_t START, END;
    void __stTIME();
    void __enTIME();
    void __IOPUT();
    using namespace std;
    
    const int maxn = 46656 + 10;
    const int mxState = 46656;
    const int maxLen = 110 + 10;
    const int INF = 0x3f3f3f3f;
    
    int to_ten(int c[])///将六进制转十进制
    {
        int ret = 0;
        for(int i=0; i<6; i++){
            ret = ret * 6 + c[i];
        }return ret;
    }
    
    inline void to_six(int num, int c[])///十进制转六进制(存在 c 中)
    {
        for(int i=5; i>=0; i--){
            c[i] = num % 6;
            num /= 6;
        }
    }
    
    int Cost[mxState];///存储操作 2 的花费
    
    int g[6][6];///存储原本 s2 => s1 只通过 1 操作所用的花费
                ///比如 g[1][2] = 3 将 s2 的 1 变成 s1 的 2 只用 1 操作要进行 3 次
    
    int cnt[6];///存储 s2 中每个数字出现的次数
    
    char s1[maxLen], s2[maxLen];
    
    inline void BFS()
    {
        int c[6] = {0, 1, 2, 3, 4, 5};
    
        int FirState = to_ten(c);
        mem(Cost, INF);
        Cost[FirState] = 0;
    
        queue<int> que;
        que.push(FirState);
        while(!que.empty()){
            int T = que.front(); que.pop();
    
            to_six(T, c);
    
            for(int i=0; i<6; i++){
                for(int j=0; j<6; j++){
                    int tmp[6];
                    memcpy(tmp, c, sizeof(tmp));
                    for(int k=0; k<6; k++)
                        if(tmp[k] == i)
                            tmp[k] = j;
    
                    int newState = to_ten(tmp);
    
                    if(Cost[newState] > Cost[T] + 1){
                        Cost[newState] = Cost[T] + 1;
                        que.push(newState);
                    }
                }
            }
        }
    }
    
    int main(void){__stTIME();__IOPUT();
    
        BFS();
    
        while(~scs(s1)){
            scs(s2);
            int len = strlen(s1);
            mem(cnt, 0);
            mem(g, 0);
            for(int i=0; i<len; i++){
                int ch1 = s1[i] - '1';
                int ch2 = s2[i] - '1';
                cnt[ch2]++;
                g[ch2][ch1]++;
            }
    
            int ans = INF;
            int c[6];
            for(int i=0; i<mxState; i++){///枚举中间状态
                to_six(i, c);
                int cost = Cost[i];///将 s2 => 中间状态 的花费
                for(int j=0; j<6; j++)///进行操作 1 的花费计算
                    cost += cnt[j] - g[j][c[j]];///举个例子就好理解一点、比如 s1="001" 、s2="112"、用这个例子去模拟
                ans = min(ans, cost);
            }
    
            printf("%d
    ", ans);
    
        }
    
    __enTIME();return 0;}
    
    
    void __stTIME()
    {
        #if _TIME
            START = clock();
        #endif
    }
    
    void __enTIME()
    {
        #if _TIME
            END = clock();
            cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
        #endif
    }
    
    void __IOPUT()
    {
        #if _INPUT
            freopen("in.txt", "r", stdin);
        #endif
        #if _OUTPUT
            freopen("out.txt", "w", stdout);
        #endif
    }
    View Code
  • 相关阅读:
    Java学习8.17
    Java学习8.16
    Java学习8.15
    Java学习8.14
    Java学习8.13
    Java学习8.12
    Java学习8.11
    131. Palindrome Partitioning 回文串分割
    40. Combination Sum II 不允许使用重复元素
    39. Combination Sum 凑出一个和,可以重复用元素(含duplicates)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/9739937.html
Copyright © 2011-2022 走看看