hdu 4770 Lights Against Dudely(暴力搜索)

来源:互联网 发布:路由器升级软件 编辑:程序博客网 时间:2024/04/29 13:11

本题的一个关键点在于需要照亮的房间最多只有15个,所以可以暴力枚举这15个点的状态,2^15=32768是一个很小的数。


枚举的程序很容易想到是递归的,因为只有递归会产生指数级的状态,for循环只能是多项式阶的。

顺时针做一个dir方向数组,可以节省很多代码。


枚举时先不考虑特殊灯,枚举一个只有普通灯和不放灯的状态。

枚举的思路是先判断该状态是否照到了#,遍历这15个点能照到的范围如果有#,则方案不合法。

然后在判断是不是所有点都被照到了,对于每一个点,遍历所有的点看有没有能照到它的。如果有一个点,所有点都照不到它,方案也不合法。

如果合法,就更新解。

然后考虑特殊灯。

把特殊灯看做3种灯分别对应三个方向,比较好写。

枚举每一个点换成这三种特殊灯的状态是否合法,如果合法更新解。


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <map>#include <queue>#include <vector>#include <cmath>#include <algorithm>using namespace std;int N,M,Num;struct node{int x,y;int p;}G[20];int dir[5][2]={{0,0},{-1,0},{0,1},{1,0},{0,-1}};int res;int Map[205][205];bool check2(int i){    for(int k=1;k<=Num;k++){int j=G[k].p;if(j==0) continue;int tx1=G[k].x+dir[j][0];int ty1=G[k].y+dir[j][1];if(tx1==G[i].x&&ty1==G[i].y) return 1;if(j==4) j=1;else j++;int tx2=G[k].x+dir[j][0];int ty2=G[k].y+dir[j][1];if(tx2==G[i].x&&ty2==G[i].y) return 1;} return 0;}bool check(){for(int i=1;i<=Num;i++){int j=G[i].p;if(j==0) continue;int tx1=G[i].x+dir[j][0];int ty1=G[i].y+dir[j][1];if(j==4) j=1;else j++;int tx2=G[i].x+dir[j][0];int ty2=G[i].y+dir[j][1];if(Map[tx1][ty1]||Map[tx2][ty2]) return 0;}for(int i=1;i<=Num;i++){if(G[i].p>=1) continue;if(!check2(i)) return 0; }return 1;}void f(int x){if(x==Num+1){if(check()){int tmp=0;for(int i=1;i<=Num;i++){if(G[i].p>=1) tmp++;}res=min(res,tmp);} for(int i=1;i<=Num;i++){int t=G[i].p;for(int j=2;j<=4;j++){G[i].p=j;if(check()){int tmp=0;for(int k=1;k<=Num;k++){if(G[k].p>=1)tmp++;}res=min(res,tmp);}}G[i].p=t;}return ;}for(int i=0;i<=1;i++){G[x].p=i;f(x+1);}}int main(){while(~scanf("%d%d",&N,&M)){if(!N&&!M) break;Num=0;memset(Map,0,sizeof(Map));memset(G,0,sizeof(G));char ch;for(int i=1;i<=N;i++){for(int j=1;j<=M;j++){scanf(" %c", &ch);if(ch=='#'){Map[i][j]=1;}else if(ch=='.'){Map[i][j]=0;G[++Num].x=i;G[Num].y=j;G[Num].p=0;}}}res=1000;if(Num==0){cout<<0<<endl;continue;}f(1);if(res==1000) res=-1;cout<<res<<endl;}return 0;}


0 0
原创粉丝点击