The New Villa

时间:2024-01-22 09:16:53

题目:The New Villa

题目链接:http://poj.org/problem?id=1137

题目大意:

  一个人买了一个别墅,里面有很多房间,特别的是这个别墅的房间里灯的开关是乱套的,也就是说房间1可能没有房间1的灯的开关,而有房间2和房间3的开关,现在从房间1出发,刚开始只有房间1是亮的,只能走到亮着的房间(还必须有门相通),现在问你走到房间n,并且只剩下房间n是亮着的步骤,如果有多个方法,输出步骤最少的。

题目思路:

  啥也不说,n最大为10,暴力搜,注意剪枝就可以了。。。附上我的代码和代码解析,不过我的代码并不怎么给力,最后时间还是需要250。。。

 #include<stdio.h>
#include<string.h>
bool door[][]; //门
bool sw[][]; //如果i能控制j的灯,那么sw[i][j]=1
int light; //当前灯的状态,从0到1024
int n; //房间的总数量
int count[][]; //某一扇门被经过的次数,可以用来控制递归次数,减少时间
int num[]; //记录房间开关的所有状态数量,达不到1024
int nu[][]; //记录每个房间开关的所有状态
bool OK() //判断是否只有卧室灯开着,结束判断为当前位置为卧室且OK()
{
if(light^(<<(n-))) return false;
return true;
}
void Init() //初始化,处理每个房间开关可能的状态
{
for(int i=;i<=n;i++)
{
for(int j=;j<;j++)
{
if((<<(i-))&j) continue; //不允许关掉自己房间的灯
int o;
for(o=;o<;o++)
{
if(sw[i][o]==) continue;
if((<<(o-))&j) break; //如果没有该房间的控制权,不允许对其进行操作
}
if(o<) continue;
nu[i][num[i]++]=j;
}
}
}
void dis(int tmp) //测试用。。。。
{
int co=;
while(tmp)
{
printf("%d ",tmp&);
tmp>>=;
co++;
}
co=-co;
while(co--)
{
printf("0 ");
}
printf("\n");
} int s[][]; //保存当前的步骤情况
int mint[][],mino; //保存所有能成功的步骤中步骤最小的
bool v[][]; //保存是否遇到过这种情况,与下面的结合使用
int vum[][]; //vum[i][j]表示当前处在房间i,灯的状态为j,最小的步骤,剪枝用
bool match; //是否能完成任务
void DFS(int i,int step)
{
if(v[i][light]&&step>=vum[i][light]) return ;
//因为下面有个剪枝,通过0状态过去的和这个一样。不在这里刷新值是为了在下面的可以把step>=的都排除掉,更快。
for(int j=;j<num[i];j++)
{
int k=nu[i][j]; //可行的开关执行方案
int tmp=light; //保存原来的灯状态
light^=k; //操作开关
int pre_step=step; //保存原来的步骤
for(int o=;o<=n;o++) //记录步骤
{
if((<<(o-))&k)
{
s[step++][]=o;
}
}
if(v[i][light]&&step>=vum[i][light]) //剪枝
{
light=tmp;
step=pre_step;
continue;
}
v[i][light]=;
vum[i][light]=step;
if(i==n&&OK()) //如果完成操作
{
if(step<mino)
{
for(int o=;o<step;o++)
{
mint[o][]=s[o][];
mint[o][]=s[o][];
}
mino=step;
}
match=;
light=tmp;
return ;
}
for(int j=;j<=n;j++)
{
if(door[i][j]==&&(light&(<<(j-)))) //如果有门相通
{
count[i][j]++;
if(count[i][j]>n-)
{
count[i][j]--;
continue;
}
s[step][]=j;
DFS(j,step+); //进入下一个房间
s[step][]=-; //只在这里进行恢复,因为这里的恢复比恢复s[step][0]的快很多
count[i][j]--;
}
}
light=tmp;
step=pre_step;
}
}
void solve() //展示步骤
{
int light=;
printf("The problem can be solved in %d steps:\n",mino);
for(int i=;i<mino;i++)
{
if(mint[i][]==-)
{
if(light&(<<(mint[i][]-)))
{
printf("- Switch off light in room %d.\n",mint[i][]);
}
else
{
printf("- Switch on light in room %d.\n",mint[i][]);
}
light^=(<<(mint[i][]-));
}
else
{
printf("- Move to room %d.\n",mint[i][]);
}
}
}
int main()
{
int m,k,a,b,cas=;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
if(n==&&m==&&k==) break;
memset(door,,sizeof(door));
for(int i=;i<m;i++)
{
scanf("%d%d",&a,&b);
door[a][b]=;
door[b][a]=;
}
memset(sw,,sizeof(sw));
memset(num,,sizeof(num));
for(int i=;i<k;i++)
{
scanf("%d%d",&a,&b);
sw[a][b]=;
}
Init();
light=;
memset(s,-,sizeof(s));
mino=;
match=;
memset(v,,sizeof(v));
DFS(,);
printf("Villa #%d\n",cas++);
if(match==)
{
solve();
printf("\n");
}
else printf("The problem cannot be solved.\n\n");
}
return ;
}