[ZOJ1301][POJ1137] The New Villa

这篇博客主要分享了解决ZOJ1301和POJ1137题目——The New Villa的心得。博主指出,问题的关键在于状态不超过1024*10种,每种状态有30种可能的操作,可以通过广度优先搜索解决。在编写输出部分时,博主发现步骤数量的单复数形式会直接影响答案的正确性,并且操作步骤与短线之间必须有空格,这是从样例输出中发现的细节问题。文章附有源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值