题目链接:https://vjudge.net/problem/UVALive-7263

或者:http://hihocoder.com/problemset/problem/1251

 

 

题目大意:给你两个字符串,问你从一个变成另一个的最少变化次数。变化规则有二,一是将某一字符变成另一个字符,二是将某一类字符变成另一类字符,都算变化一次。

 

题解:首先有一个弯要转过来,就是先进行第二种变化,再进行第一种变化。我们首先暴力出所有的变化的可能性,以及变过去需要的变化次数,然后再进行变化一,加上变化一的次数。

比如:

初始: 1 2 3 4 5 6

目标: 1 2 3 3 6 5

表示的变化是所有初始中的4最后变成3,所有初始中的5最后变成6,所有初始中的6最后变成5,通过BFS搜出最少变化次数为4,即依次为:4变3,6变4,5变6,4变5。然后再遍历字符串进行变化一。

代码:

 

#include <bits/stdc++.h>
#define N 50000
using namespace std;

void turn_to(int x,int *a)                  //10进制变6进制
{
    for (int i=5;i>=0;i--,x/=6) a[i]=x % 6;
}
int turn_back(int *a)                           //6进制变10进制
{
    int t=0;
    for (int i=0;i<6;i++)t=t*6+a[i];
    return t;
}

int f[N];
string a,b;
int G[10][10],r[10];
queue<int>q;

void presolve()                 //BFS最小变化次数
{
    while (!q.empty())q.pop();
    int a[10]={0,1,2,3,4,5},c[10];
    int t=turn_back(a);
    memset(f,0x3f,sizeof f);
    f[t]=0;
    q.push(t);
    while (!q.empty())
    {
        int x=q.front();q.pop();
        turn_to(x,a);
        for (int i=0;i<6;i++)for (int j=0;j<6;j++)    //暴力所有可能的变化
        {
            memcpy(c,a,sizeof a);
            for (int k=0;k<6;k++) if (c[k]==i) c[k]=j; //将当前状态中的所有i变为j
            t=turn_back(c);
            if (f[t]>f[x]+1)
            {
                f[t]=f[x]+1;
                q.push(t);
            }
        }
    }
}

int main()
{
    int x[10];
    presolve();
    while(cin>>b>>a)
    {
        memset(G,0,sizeof G);
        memset(r,0,sizeof r);
        for (int i=0;i<a.length();i++)
        {
            int u=a[i]-'1',v=b[i]-'1';
            r[u]++;
            G[u][v]++;
        }
        int ans=1e8;
        for (int i=0;i<N-10;i++)            //枚举所有变化
        {
            int t=f[i];
            turn_to(i,x);
            for (int j=0;j<6;j++) t+=r[j]-G[j][x[j]];   //变化一
            ans=min(ans,t);
        }
        printf("%d\n",ans);
    }
}