Today Is a Rainy Day(传送门)
题意
给定两个字符串 s1 和 s2 ,将 s2 变为 s1 ,变化操作有以下两种:
- 将一个位置上的数字变为另外一个数字
- 将一种数字变为另外一种数
求最小代价
解题思路
做题的时候仔细的思考过,先进行第二种变化比先第一种优(俺无法证明,有些疑惑),当然当时基本能才猜出是这样处理,接下来则是如何进行处理?
对于第二种变化,我们可以用
BFS
进行处理,求出将匹配状态变为不匹配状态最少需要多少步。
说的匹配状态变为不匹配状态的意思如下:
{1,2,3,4,5,6}−>{1,2,3,4,5,6}
这个只需要 0 步,将第一种与第二种匹配
这个则需要 1 <script type="math/tex" id="MathJax-Element-2652">1</script>步,将第一种与第二种匹配
求完种类变化的,接下则是一个一个变化的,直接进行计算经过种类变化后需要第一种变化多少次才能变为最终的结果即可
总的来说,这道题还是非常经典,不仅对于猜想还是去直接证明,当然直接证明不会,很尴尬,但是猜想出先进行完第二种然后进行第一种还是比较简单的,难点基本就是用BFS处理出种类变化的效果即可,比较有意思
代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 5e4 + 5;
const int MAXM = 1e2 + 20;
const int INF = 0x3f3f3f3f;
const int mod = 1e8 + 7;
char s1[MAXM], s2[MAXM];
char l[MAXM], g[MAXM][MAXM];
int dp[MAXN];
int idx(int c[]) {
int ret = 0;
for(int i = 0; i < 6; i ++) {
ret = ret * 6 + c[i];
}
return ret;
}
void rdix(int s, int c[]) {
for(int i = 5; i >= 0; i --) {
c[i] = s % 6;
s /= 6;
}
}
void BFS() {
memset(dp, 0x3f, sizeof(dp));
int c[6] = {0, 1, 2, 3, 4, 5}, s = idx(c), tmp[6];
queue<int>Q;
dp[s] = 0;
Q.push(s);
while(!Q.empty()) {
int s = Q.front();
Q.pop();
rdix(s, c);
for(int i = 0; i < 6; i ++) {
for(int j = 0; j < 6; j ++) {
memcpy(tmp, c, sizeof(tmp));
for(int k = 0; k < 6; k ++) {
if(tmp[k] == i) {
tmp[k] = j;
}
}
int ns = idx(tmp);
if(dp[ns] > dp[s] + 1) {
dp[ns] = dp[s] + 1;
Q.push(ns);
}
}
}
}
}
int main() {
BFS();
while(~scanf("%s%s", s1, s2)) {
int len = strlen(s1);
memset(l, 0, sizeof(l));
memset(g, 0, sizeof(g));
for(int i = 0; i < len; i ++) {
int c1 = s1[i] - '1', c2 = s2[i] - '1';
l[c2] ++;
g[c2][c1] ++;
}
int tmp[6];
int mins = INF;
for(int i = 0; i < MAXN; i ++) {
int sum = dp[i];
rdix(i, tmp);
for(int j = 0; j < 6; j ++) {
sum += l[j] - g[j][tmp[j]];
}
mins = min(mins, sum);
}
printf("%d\n", mins);
}
return 0;
}