农夫过河问题这里用的是动态规划吗?能解释下吗

昵称是可以中文吗 2010-12-19 02:31:03
过河
Time Limit: 1000MS Memory limit: 65536K
题目描述
农夫每天去种地都要过一条河,这条河很宽,过河要走上面的木桩。木桩有n支,排成一排,从左岸延伸到右岸,编号从1到n。左岸在1号桩的左边,右岸在n号桩的右边。但这些木桩会定时升降,因此每天他都花不少时间在过河上。所以他想找一种最快过河的方法。

在时刻0,农夫在左岸,他要在最短时间内到达右岸。在任何时刻,每一支桩都只能处于升或降的其中一种状态。升起的桩可以站上去,农夫只能站在升起的桩上或岸上。

每一支桩在时刻0都是降的状态,接着升起A分钟,降下B分钟,再升起A分钟后,再降下B分钟后,这样一直交替升降下去。例如:A=2,B=3的桩,在时刻0降,在时刻1,2升,在时刻3,4,5降,等等。A和B是常数时间,而且对于每一支桩都可能不同。

设在时刻t农夫站在p桩,那么在时刻t+1,农夫能走到p桩的左右5个桩上或岸上,也可以原地不动,当然桩是可站立的。例如,在5号桩,他能走到1,2,3,4,5,6,7,8,9,10号桩,或到左岸。

请帮农夫找一种能最快到达右岸的方法。
输入
输入数据第一行是桩的数目n(5 < n <= 1000)。接下来的n行每一行有两个整数A和B(1<=A,B<=5),用一个空格隔开。按从1到n的顺序描述每一支桩的升和降的间隔时间。
输出
输出数据只有一行,即最早到达右岸的时刻。当不可能到达右岸时,输出“NO”。
示例输入
10
1 1
1 1
1 1
1 1
2 1
1 1
1 1
1 1
1 1
1 1示例输出
4
...全文
456 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
JackBurd 2012-11-06
  • 打赏
  • 举报
回复
//我称这个题为随时间t变化的动态广度搜索问题,本层扩展前必须将上层节点扩展完毕,这是与其它广搜题最大的区别

#include<iostream>

using namespace std;

const int MAX = 1000;
const int SIZE = 1000000;
const int DN = 0;
const int UP = 1;

int a[MAX][3];        //每根桩升降的时间间隔
int mark[100][MAX];   //标记t时刻某根桩上是否已经站了人,防止重复站人,大大提高效率
int state[MAX];       //记录时间t时各桩的升降状态
int front, rear;

struct Queue
{
	int pos;  //所在位置(即哪个桩上)
	int time; //本次所处时间
}q[SIZE];

int min(int a, int b)
{
	return(a < b ? a : b);
}

void Push(int t, int pos)
{
	if(mark[t][pos])  return;  //若当前时间下该状态已入队,则不再入队,避免重复扩展,大大减少了扩展次数

	q[++rear].pos = pos; 
	q[rear].time = t;

	mark[t][pos] = 1;  //置标记为1,表示已入队
}

void main()
{
	int n;
	int cur;
	int len = 1;

	cin >> n;
	
	while(len <= n)
	{
		cin >> a[len][0] >> a[len][1];
		
		a[len][2] = a[len][0] + a[len][1];  //计算出每次完整时间周期,减少在队列中的重复运算
		
		len ++;
	}
	
	front = rear = -1;
	q[++rear].pos = 0;
	q[rear].time = 0;
	
	for(int t = 1; ; t ++)
	{   
		while(q[front].time == t-1)  //队列按时间t分层,在本层扩展时上层的必须扩展完毕,这样才能保证求到最短时间                      
		{                             
			cur = q[++front].pos;  //出队,开始扩展节点
			
			if(cur == len)  //到达对岸便输出最短时间,并退出程序
			{
				cout << endl << q[front].time << endl;

				exit(0);
			}

			state[0] = state[len] = UP;  //左右两岸始终设为UP,便于处理
            mark[t][cur] = 0;  //始终可以站在原桩上,标记为0,可扩展
			Push(t, cur);
			
			for(int i = 1, mod = 0; i < len; i ++)
			{
				mod = t % a[i][2];
				state[i] = (mod && mod <= a[i][0] ? UP : DN);  //得到每个桩当前时间的状态
			}
			
			for(int j = cur+1; j <= min(cur+5,len); j ++)
			{
				if(state[j] == DN) 	break;  //如果将上的桩是下降状态,则停止前进
				
				Push(t, j);
			} //不必再跑到(当前桩)前5个桩上去了,即使此时没有桩可以上也可以停在原桩上,而不必再后退到前面的桩上;
			  //退一步讲,即使前面5个某桩可以跳到原桩前面,那原桩必然也可以走到此处,因为这段肯定都是上升状态
              //而且说不定还可以走得更远,所以无论如何都不需要往后退到前5个桩上,题目说能走到前面5个桩上实际是个干扰
		}            
	}                       
}
JackBurd 2012-10-17
  • 打赏
  • 举报
回复
这个题目有点意思,先mark下,日后解决。
xiedaixin 2010-12-28
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 hnuqinhuan 的回复:]
用一个标记位就可以了啊
[/Quote]
这个啊
  • 打赏
  • 举报
回复
哪位大侠能不能给点思路啊
無_1024 2010-12-21
  • 打赏
  • 举报
回复
用一个标记位就可以了啊
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 hnuqinhuan 的回复:]

用一个标记位就可以了啊
[/Quote]
??能具体点吗

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧