题目链接:
[HDU 2977]Color Squares[BFS]
题意分析:
在一个3X3的格子中,可以染上蓝红绿黄,分别得分:B、R、G、Y(B <= R <= G <= Y)。格子间染色有如下规则:
1.蓝色格子可以在任何位置上染色
2.红色格子只能在蓝色格子旁边才能染色
3.绿色格子必须周围至少有一个蓝色格子和一个红色格子才能染色
4.黄色格子必须周围至少有一个蓝色格子、一个红色格子、一个绿色格子才能染色
一个格子可以被重复染色,取最新的颜色作为格子颜色。
问:最少染多少步才能使得格子的分数之和>= W。如果不能,输出无解。
解题思路:
使用BFS枚举棋盘的状态。用一个九维数组标记状态。dp[i][j][k][l]记录棋盘中有i个蓝色、j个红色、k个绿色、l个黄色所需要的最少步骤。
每个状态,枚举下一个棋盘的状态即可。
注意细节,比如对一些状态的还原。
个人感受:
把整个棋盘存下来太机智了。九维数组威武!!反正特别喜欢这题~
这题看了题解去写,第一个版本用string来记录棋盘,结果慢死了,投机取巧失败+1。
然后是标记棋盘颜色时,忘记考虑棋盘原先的颜色了。总之,收益颇多。
状态这种东西,太神奇了。
具体代码如下:
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 111;
bool vis[5][5][5][5][5][5][5][5][5];
int dp[10][10][10][10];
int dir[2][4] = {1, -1, 0, 0, 0, 0, 1, -1};
struct S {
int mp[3][3];
int step;
int num[5];
S(){
memset(mp, 0, sizeof mp);
step = 0;
memset(num, 0, sizeof num);
}
};
void bfs() {
queue<S> q;
S fst;
q.push(fst);
vis[0][0][0][0][0][0][0][0][0] = 1;
while (q.size()) {
S u = q.front(); q.pop();
dp[u.num[1]][u.num[2]][u.num[3]][u.num[4]] = min(u.step, dp[u.num[1]][u.num[2]][u.num[3]][u.num[4]]);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
int org = u.mp[i][j];
// blue
if (u.mp[i][j] != 1) {
++u.step;
++u.num[1];
--u.num[org];
u.mp[i][j] = 1;
if (!vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]]) {
vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]] = 1;
q.push(u);
}
u.mp[i][j] = org;
++u.num[org];
--u.num[1];
--u.step;
}
// red
int num1 = 0, num2 = 0, num3 = 0;
for (int k = 0; k < 4; ++k) {
int nx = i + dir[0][k], ny = j + dir[1][k];
if (0 <= nx && nx < 3 && 0 <= ny && ny < 3) {
if (u.mp[nx][ny] == 1)
++num1;
}
}
if (num1 && u.mp[i][j] != 2) {
++u.step;
++u.num[2];
--u.num[org];
u.mp[i][j] = 2;
if (!vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]]) {
vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]] = 1;
q.push(u);
}
u.mp[i][j] = org;
++u.num[org];
--u.num[2];
--u.step;
}
// green
num1 = 0, num2 = 0, num3 = 0;
for (int k = 0; k < 4; ++k) {
int nx = i + dir[0][k], ny = j + dir[1][k];
if (0 <= nx && nx < 3 && 0 <= ny && ny < 3) {
if (u.mp[nx][ny] == 1)
++num1;
if (u.mp[nx][ny] == 2)
++num2;
}
}
if (num1 && num2 && u.mp[i][j] != 3) {
++u.step;
++u.num[3];
--u.num[org];
u.mp[i][j] = 3;
if (!vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]]) {
vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]] = 1;
q.push(u);
}
u.mp[i][j] = org;
++u.num[org];
--u.num[3];
--u.step;
}
// yellow
num1 = 0, num2 = 0, num3 = 0;
for (int k = 0; k < 4; ++k) {
int nx = i + dir[0][k], ny = j + dir[1][k];
if (0 <= nx && nx < 3 && 0 <= ny && ny < 3) {
if (u.mp[nx][ny] == 1)
++num1;
if (u.mp[nx][ny] == 2)
++num2;
if (u.mp[nx][ny] == 3)
++num3;
}
}
if (num1 && num2 && num3 && u.mp[i][j] != 4) {
++u.step;
++u.num[4];
--u.num[org];
u.mp[i][j] = 4;
if (!vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]]) {
vis[u.mp[0][0]][u.mp[0][1]][u.mp[0][2]][u.mp[1][0]][u.mp[1][1]][u.mp[1][2]][u.mp[2][0]][u.mp[2][1]][u.mp[2][2]] = 1;
q.push(u);
}
u.mp[i][j] = org;
++u.num[org];
--u.num[4];
--u.step;
}
}
}
}
}
void init() {
memset(vis, 0, sizeof vis);
memset(dp, 0x3f, sizeof dp);
bfs();
}
int main()
{
init();
int b, r, g, y, w, kase = 0;
while (~scanf("%d", &b) && b) {
printf("Case %d: ", ++kase);
scanf("%d%d%d%d", &r, &g, &y, &w);
int ans = INF;
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
for (int k = 0; k < 10; ++k) {
for (int l = 0; l < 10; ++l)
if (b*i + r*j + g*k + l*y >= w) {
ans = min(ans, dp[i][j][k][l]);
}
}
}
}
if (ans == INF) printf("Impossible\n");
else printf("%d\n", ans);
}
return 0;
}