Loading

POJ 2922

Honeymoon Hike

题目链接;

解题思路

这道题主要使用了搜索,二分,枚举算法,
对于搜索:DFS的时间复杂度为O(V+E),V <= 10000 ,E <= 40000;
对于二分:时间复杂度 为 lg(n); n<=200;
对于枚举:时间复杂度为 :O(n); n <= 200;
所以总体的计算量上限为 :8 * 200 * 50000 = 8 * 10^7;
题目要求的时间限制为:5s;大约的计算量为5 * 10^7;基本满足题目要求;

实现1:非递归版DFS + 二分 + 枚举

这里出现了超时

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>

using namespace std;
int a[105][105];
int vis[105][105];
int n;
#define INF 0x7fffffff
struct Nod
{
	int x;
	int y;
	Nod(){
	}
};
int x[4]={-1,1,0,0};
int y[4]={0,0,-1,1};
bool dfs(int si,int sj,int low,int high)
{
	memset(vis,0,sizeof(vis));
	stack<Nod>st;
	Nod tmp;
	tmp.x = si;
	tmp.y = sj;
	st.push(tmp);
	vis[si][sj] = 1;
	if(a[si][sj] < low || a[si][sj] > high) return false;
	while(!st.empty())
	{
		Nod now = st.top();
		int nowi = now.x;
		int nowj = now.y;
		if(nowi == n && nowj == n) return true;
		int ni,nj;
		bool noFind =true;
		for(int i = 0; i < 4; ++i)
		{
			ni = nowi + x[i];
			nj = nowj + y[i];
			if(ni > 0 && ni <= n && nj > 0 && nj <= n)
			{
				if(!vis[ni][nj])
				{
					vis[ni][nj] = 1;
					if(!(a[ni][nj] >= low && a[ni][nj] <= high)) continue;
					tmp.x = ni;
					tmp.y = nj;
					st.push(tmp);
					noFind = false;
					break;
				}
			}
		}
		if(noFind)
		st.pop();
	}
	return false;
}
bool check(int low,int high,int d)
{
	int e = high - d;
	for(int i = low; i <= e; ++i)
	{
		if(dfs(1, 1, i, i + d))
		{
			return true;
		}
	}
	return false;
}

bool input(int order)
{
	scanf("%d",&n);
	int low = INF,high = -1;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= n; ++j)
		{
			scanf("%d",&a[i][j]);
			if(a[i][j] < low)
			{
				low = a[i][j];
			}else if(a[i][j] > high){
				high = a[i][j];
			}
		}
	}
	int mid;
	int max_d = high - low;
	int L = 0;
	int R = max_d + 1;
	while(L < R)
	{
		mid = (L + R) >> 1;
		if(check(low, high, mid))R = mid;
		else L = mid + 1;
	}
	printf("Scenario #%d:\n",order);
	printf("%d\n",R);
	printf("\n");
	return true;	
} 
int main()
{
	int T;
	scanf("%d",&T);
	for(int i = 1; i <= T; ++i)
	{
		input(i);
	}
	return 0;
}

实现2:递归DFS + 二分 + 枚举(通过)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>

using namespace std;
int a[105][105];
int vis[105][105];
int n;
#define INF 0x7fffffff
int x[4]={-1,1,0,0};
int y[4]={0,0,-1,1};
bool dfs(int si,int sj,int low,int high)
{
	
	if(!(a[si][sj] >= low && a[si][sj] <= high)) return false;
	if(si == n && sj == n) return true;
	int  nowi, nowj, ni, nj;
	nowi = si;
	nowj = sj;
	for(int i = 0; i < 4; ++i)
	{
		ni = nowi + x[i];
		nj = nowj + y[i];
		if(ni > 0 && ni <= n && nj > 0 && nj <= n)
		{
			if(!vis[ni][nj])
			{
				vis[ni][nj] = 1;
				if(dfs(ni,nj,low,high)) return true;
			}
		}
	}
	return false;
}
bool check(int low,int high,int d)
{
	int e = high - d;
	for(int i = low; i <= e; ++i)
	{
		memset(vis,0,sizeof(vis));
		if(dfs(1, 1, i, i + d))
		{
			return true;
		}
	}
	return false;
}

bool input(int order)
{
	scanf("%d",&n);
	int low = INF,high = -1;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= n; ++j)
		{
			scanf("%d",&a[i][j]);
			if(a[i][j] < low)
			{
				low = a[i][j];
			}else if(a[i][j] > high){
				high = a[i][j];
			}
		}
	}
	int mid;
	int max_d = high - low;
	int L = 0;
	int R = max_d + 1;
	while(L < R)
	{
		mid = (L + R) >> 1;
		if(check(low, high, mid))R = mid;
		else L = mid + 1;
	}
	printf("Scenario #%d:\n",order);
	printf("%d\n",R);
	printf("\n");
	return true;	
} 
int main()
{
	int T;
	scanf("%d",&T);
	for(int i = 1; i <= T; ++i)
	{
		input(i);
	}
	return 0;
}

参考

https://blog.csdn.net/u013480600/article/details/26097213

posted @ 2018-07-30 10:18  lif323  阅读(164)  评论(0编辑  收藏  举报