1. 程式人生 > >UVALive - 7263 Today Is a Rainy Day(bfs)

UVALive - 7263 Today Is a Rainy Day(bfs)

二次 變換 net -- bfs math font 字符串 print

原題鏈接

題意

給兩個等長的只含數字1,2,3,4,5,6的字符串s(|s|≤110),有兩種操作:

- 把一個位置的數字換成另一個數字,換成的數字也只能是1到6
- 把這個字符串中相同的數字都換成另一種數字
應用上面的兩種操作把第二個字符串轉換成第一個字符串至少需要多少次操作?

分析
首先盡可能多的進行第二次操作一定是最優的。
對於第二種操作,我們可以預處理出來變換到每個狀態的最短步數,也就是用bfs跑。以123456標記為初始狀態state,然後每次選擇一個要變換的數字以及變換成的數字。
那麽,如何求解從第二個字符串變到第一個字符串的最少步數呢?根據上面的狀態定義,初始狀態為123456(位置1對應數字1,位置2對應數字2....)

,那麽每到一個新的狀態nxt,先用數組存起來對應位置的change[],遍歷s2,如果change[s2[j]]!=s1[j](change[s2[j]]表示s2[j]在nxt狀態下變成了change[s2[j]]),則需要進行操作1,tmp++。
那麽遍歷所有狀態,ans=min(ans,tmp+step[nxt])

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
using
namespace std; const int MAX_N = 1000000; int total = 0, step[MAX_N], res[MAX_N], pw10[8]; queue<int> que; char s1[120], s2[120]; void bfs() { pw10[0] = 1; for (int i = 1; i <= 7; ++i) { pw10[i] = 10 * pw10[i - 1]; } memset(step, -1, sizeof (step)); int st = 123456; step[st]
= total, res[total++] = st; que.push(st); while (!que.empty()) { int cur = que.front(); que.pop(); for (int i = 1; i <= 6; ++i) { for (int j = 1; j <= 6; ++j) { if (i == j) continue; int nxt = 0; for (int k = 5; k >= 0; --k) { int p = cur / pw10[k] % 10; if (p == i) nxt = nxt * 10 + j; else nxt = nxt * 10 + p; } if (step[nxt] != -1) continue; step[nxt] = step[cur] + 1; res[total++] = nxt; que.push(nxt); } } } } int main() { bfs(); while (~scanf("%s%s", s1, s2)) { int len = strlen(s1); int ans = len, change[10]; for (int i = 0; i < total; ++i) { int cur = res[i], tmp = 0; for (int j = 5, k = 1; j >= 0; --j) { change[k++] = cur / pw10[j] % 10; } for (int j = 0; j < len; ++j) { int to = change[s2[j] - 0]; if (to != s1[j] - 0) tmp++; } ans = min(ans, tmp + step[cur]); } printf("%d\n", ans); } return 0; }

UVALive - 7263 Today Is a Rainy Day(bfs)