搜索 POJ 2870 Light Up

原创 2016年08月30日 22:40:55

题目链接:  POJ 2870 Light Up

分析:

求最小步数,首先想到了IDA*,但是写了1个多小时,严重超时。仔细思考后发现,步数可以达到20步以上,比如以下这个样例需要25步:

7 7
24
1 2 -1
1 4 -1
1 6 -1
2 1 -1
2 3 -1
2 5 -1
2 7 -1
3 2 -1
3 4 -1
3 6 -1
4 1 -1
4 3 -1
4 5 -1
4 7 -1
5 2 -1
5 4 -1
5 6 -1
6 1 -1
6 3 -1
6 5 -1
6 7 -1
7 2 -1
7 4 -1
7 6 -1
所以在用IDA*之前,还是要想一想步数会不会太多。

谈一谈朴素的深搜——

地图类型的搜索(例如数独) 一般都是采用一格一格的搜索,有时可以改变顺序(例如数独很多时候需要从条件最多的格子入手)。

如果按顺序搜索会有一个剪枝的方便之处,本题就用到了——后面的行极有可能无法影响前面的格子。


本题代码如下:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>

#define xx first
#define yy second
#define LL long long
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))
#define INTpair pair<int,int>

using namespace std;
const int maxn=20,inf=1e9;

int n,m,B,s[maxn][maxn],lit[maxn][maxn];
bool lamp[maxn][maxn];
int ans;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
vector<INTpair> v;

void Change(int x,int y,int type){
	//点亮(type==1)或者 熄灭(type==-1)这个点 
	int i;
	lamp[x][y]= (type==1);
	for(i=y;i>0&&s[x][i]==-2;i--)lit[x][i]+=type;
	for(i=y+1;i<=m&&s[x][i]==-2;i++)lit[x][i]+=type;
	for(i=x-1;i>0&&s[i][y]==-2;i--)lit[i][y]+=type;
	for(i=x+1;i<=n&&s[i][y]==-2;i++)lit[i][y]+=type;
}

bool check1(){  //检查带编号的墙 ,是否满足要求 
	int i,j;
	for(i=0;i<v.size();i++){
		int x=v[i].xx,y=v[i].yy,cnt=0;
		for(j=0;j<4;j++)
			if(lamp[x+dx[j]][y+dy[j]])cnt++;
		if(cnt!=s[x][y]) return false;
	}
	return true;
} 

bool check2(){  
	//剪枝1: 检查带编号的墙 ,是否已经有超过要求的,有返回false 
	int i,j;
	for(i=0;i<v.size();i++){
		int x=v[i].xx,y=v[i].yy,cnt=0;
		for(j=0;j<4;j++)
			if(lamp[x+dx[j]][y+dy[j]])cnt++;
		if(cnt>s[x][y]) return false;
	}
	return true;
} 

bool check3(int x,int y){  
	//检查(x,y)这个点会不会和已经有的灯冲突 
	int i;
	for(i=y-1;i>0&&s[x][i]==-2;i--)if(lamp[x][i])return false;
	for(i=x-1;i>0&&s[i][y]==-2;i--)if(lamp[i][y])return false;
	return true;
}

bool ALL(){  //检查是否全部点亮 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(s[i][j]==-2&&!lit[i][j])return false;
	return true;
}

bool Above(int x,int y){
	/*  强剪枝: 
		检查墙(x,y) ,如果他的正上方还有没点亮的,那之后也没法点亮 
	*/ 
	for(int i=1;i<x;i++)
		if(s[i][y]==-2&&!lit[i][y]) return true;
	return false;
}

void PrintMap(){
	cout<<"*********&&&&&&&&&&************"<<endl;
	for(int i=1;i<=n;i++,cout<<endl)
		for(int j=1;j<=m;j++)cout<<lamp[i][j]<<" ";
	cout<<"*********&&&&&&&&&&************"<<endl;
}

void DFS(int x,int y,int dep){ //当前讨论(x,y)这个点,已经放了dep个灯 
	//cout<<x<<" "<<y<<" "<<dep<<endl;
	if(dep>=ans) return ;
	if(!check2()) return ;
	if(y==1&&x==n+1&&check1()&&ALL()){
		ans=min(ans,dep);
		//PrintMap();
		return ;
	}
	if(x>n||y>m) return ;
	if(s[x][y]>=-1){    //搜到墙了 
		if(x>1&&s[x-1][y]==-2&& Above(x,y))return;
		if(y<m) DFS(x,y+1,dep);
		else DFS(x+1,1,dep);
	}
	else {
		if(y<m)DFS(x,y+1,dep);
		else DFS(x+1,1,dep);
		if(check3(x,y)){
			Change(x,y,1);
			if(y<m)DFS(x,y+1,dep+1);
			else DFS(x+1,1,dep+1);
			Change(x,y,-1);
		}
	}
}

int main(){
	int i,j,x,y;
	while(cin>>n>>m){
		if(!n&&!m) return 0;
		CLEAR(s);CLEAR(lit); CLEAR(lamp);
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)s[i][j]=-2;
		cin>>B;
		v.clear();
		for(i=1;i<=B;i++){
			cin>>x>>y;
			cin>>s[x][y];
			if(s[x][y]!=-1)v.push_back(make_pair(x,y));
		}
		ans=inf;
		DFS(1,1,0);
		if(ans==inf)cout<<"No solution"<<endl;
		else cout<<ans<<endl; 
	}
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

poj2870Light Up(迭代加深搜索)

Light Up Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 754   Accept...
  • ophunter
  • ophunter
  • 2013年07月13日 13:32
  • 901

poj 初期基本搜索

第三个专题了,初期基本搜索: 都是水题,两天完全可以刷完。。。 (1)、深度优先搜索 1、poj2488 题意:给出一个国际棋盘的大小,判断马能否不重复的走过所有格,并记录下其中按字典序排列的...
  • consciousman
  • consciousman
  • 2017年01月19日 10:37
  • 564

poj 几道简单的搜索题 (一)

题目:poj 2488 A Knight's Journey 题意: 给一个m*n的棋盘,马走日,给出一条字典序最小的马的路线来走完整个棋盘? 分析: 如果能走完棋盘,那么从(1,1)点d...
  • hjt_fathomless
  • hjt_fathomless
  • 2016年07月13日 16:24
  • 572

每日一搜——poj搜索题目分类

一些好题目 POJ 1190 – 生日蛋糕(基础,好题) http://acm.pku.edu.cn/JudgeOnline/problem?id=1190 题意:略 解法:dfs,题偏简单,但做出...
  • liujian20150808
  • liujian20150808
  • 2016年03月13日 19:30
  • 1177

BFS广度优先搜索(4)--hdu2717(poj3278)(基础题)

Catch That C Time Limit:2000MS    Memory Limit:65536KB    64bit IO Format:%lld & %llu
  • Acmer_Sly
  • Acmer_Sly
  • 2016年09月13日 00:23
  • 299

poj1087 网络最大流

http://poj.org/problem?id=1087 Description You are in charge of setting up the press room for ...
  • u013573047
  • u013573047
  • 2015年01月20日 20:42
  • 950

poj3278广度优先搜索(BFS)

哎,还是在看了人家的代码情况下才做出来的,没事,能学会就行啦,用的是c++上的stl中的函数,定义的队列,比C语言上自己定义好用多了,嘿嘿,poj上的题目真不简单,比其他oj要难我觉得,起码是比hdu...
  • sinat_22659021
  • sinat_22659021
  • 2014年12月12日 23:57
  • 726

POJ-1475(A*算法)

题目:http://poj.org/problem?id=1475 一眼看上去就能确定是BFS,但这题和普通寻找终点的BFS不一样,除了自身的位置,状态上还要体现箱子的位置。由于题目要求最少push...
  • uuuououlcz
  • uuuououlcz
  • 2015年01月07日 02:08
  • 1044

poj上搜索经典题目

声明: 1.这不是我原创的,是从网上找到的,跟大家分享一下。 2.后边标的难度是对于小菜而言的,像例如说applepi(杜神牛)这样的神牛除外。 3.放到这里还有一个原因是为了自己看...
  • nailerTT
  • nailerTT
  • 2015年01月08日 17:24
  • 838

poj 几道简单的搜索题(三)

题目:poj 2531 题意: 给出n(n 分析: n=20,暴力枚举的时间复杂度才O(2^20*C),C是求和的时间常数。2000ms的时间足够了。暴力枚举的话可以子集枚举和递归(时间接近1000...
  • hjt_fathomless
  • hjt_fathomless
  • 2016年07月15日 00:12
  • 311
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:搜索 POJ 2870 Light Up
举报原因:
原因补充:

(最多只允许输入30个字)