POJ 1137----The New Villa

9 篇文章 0 订阅
2 篇文章 0 订阅

问题描述:

The New Villa

Time Limit: 1000MS Memory Limit: 10000K

Total Submissions: 1354 Accepted: 443

Description

 

Mr. Black recently bought a villa in the countryside. Only one thing bothers him: although there are light switches in most rooms, the lights they control are often in other rooms than the switches themselves. While his estate agent saw this as a feature, Mr. Black has come to believe that the electricians were a bit absent-minded (to put it mildly) when they connected the switches to the outlets. 

 

One night, Mr. Black came home late. While standing in the hallway, he noted that the lights in all other rooms were switched off. Unfortunately, Mr. Black was afraid of the dark, so he never dared to enter a room that had its lights out and would never switch off the lights of the room he was in. 

 

After some thought, Mr. Black was able to use the incorrectly wired light switches to his advantage. He managed to get to his bedroom and to switch off all lights except for the one in the bedroom. 

 

You are to write a program that, given a description of a villa, determines how to get from the hallway to the bedroom if only the hallway light is initially switched on. You may never enter a dark room, and after the last move, all lights except for the one in the bedroom must be switched off. If there are several paths to the bedroom, you have to find the one which uses the smallest number of steps, where "move from one room to another", "switch on a light" and "switch off a light" each count as one step.

Input

 

The input file contains several villa descriptions. Each villa starts with a line containing three integers r, d, and s. r is the number of rooms in the villa, which will be at most 10. d is the number of doors/connections between the rooms and s is the number of light switches in the villa. The rooms are numbered from 1 to r; room number 1 is the hallway, room number r is the bedroom. 

 

This line is followed by d lines containing two integers i and j each, specifying that room i is connected to room j by a door. Then follow s lines containing two integers k and l each, indicating that there is a light switch in room k that controls the light in room l. 

 

A blank line separates the villa description from the next one. The input file ends with a villa having r = d = s = 0, which should not be processed.

Output

 

For each villa, first output the number of the test case ('Villa #1', 'Villa #2', etc.) in a line of its own. 

 

If there is a solution to Mr. Black's problem, output the shortest possible sequence of steps that leads him to his bedroom and only leaves the bedroom light switched on. (Output only one shortest sequence if you find more than one.) Adhere to the output format shown in the sample below. 

 

If there is no solution, output a line containing the statement `The problem cannot be solved.' 

 

Output a blank line after each test case.

Sample Input

 

3 3 4

1 2

1 3

3 2

1 2

1 3

2 1

3 2

 

2 1 2

2 1

1 1

1 2

 

0 0 0

Sample Output

 

Villa #1

The problem can be solved in 6 steps:

- Switch on light in room 2.

- Switch on light in room 3.

- Move to room 2.

- Switch off light in room 1.

- Move to room 3.

- Switch off light in room 2.

 

Villa #2

The problem cannot be solved.



这个问题太难了。我用了好几个数组在算出来。各个数组的功能见注释。问题要求:从第一个房间走到最后一个房间,中间途径的房间的灯一定得是亮着的。而且进入最后一个房间后,别的所有的房间的灯一定得是关这的。房间和房间之间用门连接(所以房间之间的关系可用无向图来表示),开关可以控制灯,但不能反过来,所以开关和灯的关系可以用一个有向图来表示。有了一个有向图和一个无向图,在搜索(用的是宽度优先搜索)的时候要注意下一个房间的灯必须是亮着的以及房间和房间之间必须连通的限制条件。这是比较好想的。本题的关键在于如何将答案以正确的格式打印出来。我写的这个程序大部分的代码都在处理路径的储存问题。下面贴代码:

#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

ifstream fin("C:\\data43.in");

#define MAXNUM 32767
int r,d,s;
int room[11][11],lightSwitch[11][11],step[11][11];//room[11][11]房间关系无向图  lightSwitch[11][11]储存开关和灯的关系 step[11][11]储存路径
int lightBeOn[11],roomOnceIn[11],stepPara[11]; //lightBeOn[11]记录灯的状态  roomOnceIn[11] 记录房间的状态  stepPara[11] 记录在途径的每一个房间的操作数
int stepTemp[11][11],stepParaTemp[11]; //stepTemp[11][11]  step[11][11]的临时数组   setpParaTemp[11]  stepPara[11]的临时数组 
int N,minstep;

void print(int pos)  
{
	if(minstep==MAXNUM)
	{
		cout<<"Villa #"<<N<<":"<<endl;
		cout<<"The problem cannot be solved."<<endl;
	}
	else
	{
		if(pos==1)
		{
			cout<<"Villa #"<<N<<":"<<endl;
			cout<<"The problem can be solved in "<<minstep<<" steps:"<<endl;
		}
		int i;
		for(i=1;i<=stepPara[pos];++i)
		{
			if(pos!=r&&i==stepPara[pos])
			{
				cout<<"-Move to room "<<step[pos][i]<<"."<<endl;
				print(step[pos][i]);
				return;
			}
			if(lightBeOn[step[pos][i]]==0)
			{
				lightBeOn[step[pos][i]]=1;
				cout<<"-Switch on light in room "<<step[pos][i]<<"."<<endl;
			}
			else
			{
				lightBeOn[step[pos][i]]=0;
				cout<<"-Switch off light in room "<<step[pos][i]<<"."<<endl;
			}
		}
	}
}

void DFSRoom(int,int);

void DFSLight(int pos,int next,int cnt,int lightpos)
{
        if(lightpos>r)
        {
		if(lightBeOn[next]==1)
		{
			stepTemp[pos][++stepParaTemp[pos]]=next;
			DPRoom(next,cnt+1);
			stepTemp[pos][stepParaTemp[pos]--]=0;
		}
		return;
        }
	if(lightSwitch[pos][lightpos]==1)
	{
		if(lightpos!=pos)
		{
			lightBeOn[lightpos]=lightBeOn[lightpos]==0?1:0;//改变灯的状态 
			stepTemp[pos][++stepParaTemp[pos]]=lightpos;
			DFSLight(pos,next,cnt+1,lightpos+1);
			lightBeOn[lightpos]=(lightBeOn[lightpos])==0?1:0;//这样写的原因见《算法竞赛入门》P111,是里面讲解的变体
			stepTemp[pos][stepParaTemp[pos]--]=0;
		}
		else
		{
			 DPLight(pos,next,cnt,lightpos+1);
		}
	}
        else
        {
		DFSLight(pos,next,cnt,lightpos+1);
        }
}

void DFSRoom(int pos,int cnt)
{
	if(pos==r)
	{
		bool isPermited=true;
		for(int i=1;i<r;++i)
		{
			if(lightSwitch[r][i]==1&&lightBeOn[i]==1&&pos!=i)
			{
				stepTemp[pos][++stepParaTemp[pos]]=i;
				lightBeOn[i]=0;
				++cnt;
			}
		}
		for(int i=1;i<r;++i)
		{
			if(lightBeOn[i]==1)
			{
				isPermited=false;
			}
		}
		if(isPermited)
		{
			if(cnt<minstep)
			{
				minstep=cnt;
				memcpy(stepPara,stepParaTemp,sizeof(stepPara));
				memcpy(step,stepTemp,sizeof(step));
			}
		}
		while(stepParaTemp[pos]!=0)
			stepTemp[pos][stepParaTemp[pos]--]=0;
		return;
	}
	for(int i=1;i<=r;++i)
	{
		if(roomOnceIn[i]==0&&room[pos][i]==1)
		{
			DFSLight(pos,i,cnt,1);
		}
	}
}

int main()
{
	N=0;
	while(fin>>r>>d>>s&&(r!=0&&d!=0&&s!=0))
	{
		int m,n;
		memset(room,0,sizeof(room));
		memset(lightSwitch,0,sizeof(lightSwitch));
		memset(step,0,sizeof(step));
		memset(stepPara,0,sizeof(stepPara));
		memset(lightBeOn,0,sizeof(lightBeOn));
		memset(roomOnceIn,0,sizeof(roomOnceIn));
		memset(stepTemp,0,sizeof(stepTemp));
		memset(stepParaTemp,0,sizeof(stepParaTemp));
		++N;
		minstep=MAXNUM;
		for(int i=0;i<d;++i)
		{
			fin>>m>>n;
			room[m][n]=1;
			room[n][m]=1;
		}
		for(int i=0;i<s;++i)
		{
			fin>>m>>n;
			lightSwitch[m][n]=1;
		}
		roomOnceIn[1]=1;
		lightBeOn[1]=1;
		DPRoom(1,0);
		memset(lightBeOn,0,sizeof(lightBeOn));
		lightBeOn[1]=1;
		print(1);
		system("pause");
	}
}

print(int)能起作用的原因:

我在对房间i进行搜索的时候,如果改变了一个开关k的状态,就把k的编号放在step[i][currentpos]下,改变了另一个开关j的状态,就把j的编号放在step[j][currentpos]中。为了打印方便,一定要先记录开关的编号,最后一个位置(stepPara[i])一定记录的是房间i之后进入的那个房间的编号(最后一个房间除外,因为进入了最后一个房间,最多吧以前亮着灯的房间的灯给关上,所以没有房间再进了)。如果画个图的话就看的很清楚了。


本题假设进过的房间就不会再进了。

这道题目太难了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值