hihocoder1251&Uvalive7263 Today Is a Rainy Day 2015北京赛区C

题意:

给出一个长度为N的串,每个元素介于1-6之间,现在有两种操作方式:
A、将所有值为x的改为y
B、将某个位置为x
现在给出初始串S,要求将其变为目标串T的最小操作次数。
N≤100


分析:

首先,必须得到一个结论,所有的B操作都可以在所有A操作做完后进行
证明非常简单:无论最优解中B操作在任意一个位置,将其在A操作做完后,将其直接改为目标串的值,这样可以是不会增加操作次数的。
所以现在就很简单了,我们可以暴力枚举A操作,很容易可以发现A操作其实是一种映射关系,我们可以bfs暴力一发,最后枚举每种操作方式,将原串根据每种操作方式进行映射,再将映射后的串用O(n)的复杂度扫描一次,若该位置的值与目标串不一样,就需要在该位置做一次B操作。再将所有的映射关系的操作次数与其需要做的B操作次数相加,就得到了一种方案。所有方案取最小值,即可求出我们要的答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define SF scanf
#define PF printf
#define MAXN 110
#define INF 0x3FFFFFFF
using namespace std;
int col[7],n,col1[7];
char s[MAXN],t[MAXN];
int vis[46656+100];
queue<int> q;
int get_num(){
    int y=1,res=0;
    for(int i=5;i>=0;i--){
        res+=col[i]*y;
        y*=6;
    }
    return res;
}
void get_id(int x){
    for(int i=5;i>=0;i--){
        col[i]=x%6;
        x/=6;
    }
} 
int check(int x){
    get_id(x);
    /*if(col[0]==1&&col[1]==1&&col[2]==2&&col[3]==3&&col[4]==4&&col[5]==5)
        PF("*");*/
    int cnt=0;
    for(int i=0;i<n;i++){
        int tx=col[s[i]-'1'];
        if(tx!=t[i]-'1')
            cnt++;
    }
    return cnt;
}
int bfs(){
    memset(vis,-1,sizeof vis);
    for(int i=0;i<6;i++)
        col[i]=i;
    int st=get_num();
    q.push(st);
    vis[st]=0;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        get_id(x);
        for(int i=0;i<6;i++)
            col1[i]=col[i];
        for(int i=0;i<6;i++)
            for(int j=0;j<6;j++){
                for(int k=0;k<6;k++)
                    if(col[k]==i)
                        col[k]=j;
                int newn=get_num();
                if(vis[newn]==-1){
                    vis[newn]=vis[x]+1;
                    q.push(newn);
                }
                for(int k=0;k<6;k++)
                    col[k]=col1[k];
            }
    }
}
int main(){
    bfs();
    while(SF("%s%s",t,s)!=EOF){
        n=strlen(s);
        int ans=INF;
        for(int i=0;i<46656;i++)
            if(vis[i]!=-1){
                ans=min(ans,check(i)+vis[i]);
            }
        PF("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值