ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1301
POJ: http://poj.org/problem?id=1137
每个房间的开关经常是控制别的房间的灯的。
Mr.Black站在走廊,灯全是熄灭的。Mr.Black怕黑,所以他不敢进入黑的屋子,也不敢关掉他所在屋子的灯。
走廊是亮的,所有屋子是黑的。不准走进黑屋子,且最后到达卧室,卧室以外的灯全灭。找到步骤最小的方式,“房间之间的移动”、“开灯”、“关灯”都算一个步骤。
解题思路:
由求最短步骤和r很小,且灯的状态可以用01表示,想到可以用广搜。
状态最多1024*10种,每种最多有10种移动方式+10种开灯方式+10种关灯方式共30种操作,时间上是允许广搜的。
注意点:
1、写输出部分的时候犹豫了一下,把步骤等于0和1的地方写了step的单数形式,步骤大于1的时候使用step复数形式,结果居然WA掉了。
2、注意操作步骤和短线"-"之间有空格,之后才注意到的,果然还是应该把sample output复制到记事本里看……
源代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 15
#define maxs 20010
#define MOVETO 20
#define SWITCHON 10
#define SWITCHOFF 0
int r;
int control[maxs]; //状态转移i由control[i]得到
int op[maxs]; //状态i通过op[i]由上一步得到
bool visited[maxs];
bool g[maxn][maxn], light[maxn][maxn];
bool init()
{
int t1, t2, d, s;
scanf("%d%d%d", &r, &d, &s);
if (r==0) return false;
memset(g, false, sizeof(g)); //g[i][j]==true 表示房间ij之间互通
for (int i=0; i<d; i++)
{
scanf("%d%d", &t1, &t2);
t1--; t2--;
g[t1][t2]=g[t2][t1]=true;
}
memset(light, false, sizeof(light)); //-1: 无控制, i控制light[i]
for (int i=0; i<s; i++)
{
scanf("%d%d", &t1, &t2);
t1--; t2--;
light[t1][t2]=true;
}
return true;
}
bool checkstay(int u)
{
int pos=u%16;
int tmp=u/16;
int j=1<<pos;
if (tmp&j) return true;
return false;
}
int bfs() //return -1 or number of steps
{
queue<int> q;
queue<int> step;
int target =(1<<(r+4-1))+r-1;
int u=(1<<4), k=0;
int u_new, uu, pos;
memset(visited, 0, sizeof(visited));
memset(control, 255, sizeof(control));
visited[u]=true;
q.push(u);
step.push(k);
while (!q.empty())
{
u=q.front(); q.pop();
k=step.front(); step.pop();
pos=u%16; uu=u>>4;
if (u==target){return k;} //状态低4位留给位置
for (int i=0; i<r; i++) //move操作
{
if (g[pos][i]) //可以从pos到房间i
{
u_new=u-pos+i;
if (!visited[u_new] && checkstay(u_new))
{
q.push(u_new); step.push(k+1); visited[u_new]=true;
control[u_new]=u;
op[u_new]=MOVETO+i;
}
}
}
for (int i=0, j=(1<<4); i<r; i++, j=j<<1, uu=uu>>1) //开关灯操作
if (light[pos][i])
{
if (uu&1)
{
u_new=u-j;
if (!visited[u_new] && checkstay(u_new))
{
q.push(u_new); step.push(k+1); visited[u_new]=true;
control[u_new]=u;
op[u_new]=SWITCHOFF+i;
}
}
else
{
u_new=u+j;
if (!visited[u_new] && checkstay(u_new))
{
q.push(u_new); step.push(k+1); visited[u_new]=true;
control[u_new]=u;
op[u_new]=SWITCHON+i;
}
}
}
}
return -1;
}
void dfsprint(int u)
{
int u_new;
if (u==(1<<4)) return;
u_new=control[u];
dfsprint(u_new);
if (op[u]>=MOVETO) printf("- Move to room %d.\n", op[u]-MOVETO+1);
else if (op[u]>=SWITCHON) printf("- Switch on light in room %d.\n", op[u]-SWITCHON+1);
else if (op[u]>=SWITCHOFF) printf("- Switch off light in room %d.\n", op[u]-SWITCHOFF+1);
}
void print(int cs, int steps)
{
printf("Villa #%d\n", cs);
if (steps==-1)
printf("The problem cannot be solved.\n");
else
{
printf("The problem can be solved in %d steps:\n", steps);
dfsprint((1<<(r+4-1))+r-1);
}
printf("\n");
}
int main()
{
int steps;
for (int cs=1; ;cs++)
{
if (!init()) break;
steps=bfs();
print(cs, steps);
}
return 0;
}