题意:
给出一个长度为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);}
}