[uvalive 7263] Today Is a Rainy Day(暴力,BFS,dp)
题目链接:https://vjudge.net/problem/UVALive-7263
题意:给两个字符串a,b,只包含1~6的数字,现在允许两种操作:1、修改某一位数字,2、修改整个串的某个数字,变成另外一个数字。问从b到a的最少操作。
首先2操作修改的比较多,假如都能打到最优解的情况下,尽可能多的2操作一定会比较优。
我们可以先不考虑字符串具体的变化,先考虑只有6位数的2操作的变化情况。
以012345为起点,预处理出需要多少种2操作才可以变成一个6为的目标串。
不必关心每一种数字有多少个,只需要关心2操作最少多少次。上述操作直接bfs就行了。
注意做法不对称:a到b和b到a结果不一样。
接下来枚举012345变成000000到555555的所有最小状态作为中间状态,由于1操作的存在,所以仅仅进行2操作是会多进行多余的操作的。所以实现记下:b到a的每一对数字的变化次数G,以及b中每一位数字出现的次数。
接下来枚举中间状态:b到中间状态是通过012345到中间状态的2操作映射获得的,那么通过这次映射以及操作,可以让b中的所有字符通过映射变成对应的字符,接下来只需要记录一共有多少位没有变到a就行了。
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 const int maxn = 66666; 6 const int inf = 0x7f7f7f7f; 7 unordered_map<string, int> id; 8 string di[maxn]; 9 int G[11][11], vis[11]; 10 int icnt, n; 11 int dp[maxn]; 12 string a, b; 13 queue<int> q; 14 string itmp; 15 16 void dfs(int cnt) { 17 if(cnt == 6) { 18 id[itmp] = icnt; di[icnt++] = itmp; 19 return; 20 } 21 for(int i = 0; i < 6; i++) { 22 string bk = itmp; 23 itmp += (i + '0'); 24 dfs(cnt+1); 25 itmp = bk; 26 } 27 } 28 29 void init() { 30 string pre, cpy; 31 itmp.clear(); pre.clear(); id.clear(); icnt = 0; 32 dfs(0); 33 for(int i = 0; i < icnt; i++) dp[i] = inf; 34 for(int i = 0; i < 6; i++) pre += (i + '0'); 35 while(!q.empty()) q.pop(); 36 q.push(id[pre]); dp[id[pre]] = 0; 37 while(!q.empty()) { 38 int pid = q.front(); q.pop(); 39 pre = di[pid]; 40 for(int i = 0; i < 6; i++) { 41 for(int j = 0; j < 6; j++) { 42 cpy = pre; 43 for(int k = 0; k < 6; k++) { 44 if(pre[k] == i + '0') cpy[k] = j + '0'; 45 } 46 int cid = id[cpy]; 47 if(dp[cid] == inf) { 48 dp[cid] = dp[pid] + 1; 49 q.push(cid); 50 } 51 } 52 } 53 } 54 } 55 56 int main() { 57 // freopen("in", "r", stdin); 58 init(); 59 while(cin >> a >> b) { 60 memset(G, 0, sizeof(G)); 61 memset(vis, 0, sizeof(vis)); 62 n = a.length(); 63 for(int i = 0; i < n; i++) { 64 int u = b[i] - '1'; 65 int v = a[i] - '1'; 66 G[u][v]++; vis[u]++; 67 } 68 int ret = inf; 69 for(int i = 0; i < icnt; i++) { 70 string mid = di[i]; 71 int tmp = dp[i]; 72 for(int j = 0; j < 6; j++) { 73 tmp += vis[j] - G[j][mid[j]-'0']; 74 } 75 ret = min(ret, tmp); 76 } 77 printf("%d\n", ret); 78 } 79 return 0; 80 }