目录
一、实验目的
1、了解贪心算法的分析过程,学会用贪心算法解决一些具体的问题。
2、了解广度优先算法和深度优先算法。
二、实验内容
- 1992
当然,我们的收藏中至少需要一个电脑游戏。典型的可以说是“镇上追逐”。在我们的案例中,笑脸叫杰克,正在穿过分成小田野的小镇。有些田地被墙覆盖,无法穿过它们。杰克收集积分,并试图避免与追逐他的怪物接触。一旦杰克吃了特殊点(或星号),情况就会颠倒过来,杰克可以吃怪物。以此类推,一次又一次。我相信你们每个人都见过这样的游戏。
在我们的例子中,城镇是随机生成的。杰克总是从左上角开始,“奖励星号”在右下角。在最困难的关卡中,只要杰克只向左和向下走几步,奖金就会消失,这些步数恰好足以从一个角落到另一个角落。如果他朝着错误的方向迈出一步,他永远无法及时到达那里。但防止被怪物抓住仍然很重要。因此,玩家必须选择最好的方式到达右下角。你要确定镇上有多少种不同的方式。
- 1042
约翰要去钓鱼。他有 h 小时可用 (1 <= h <= 16),该地区有 n 个湖泊 (2 <= n <= 25),都可以沿着一条单行道到达。约翰从1号湖开始,但他可以在任何他想要的湖结束。他只能从一个湖到下一个湖,但除非他愿意,否则他不必在任何湖停留。对于每个 i = 1,...,n - 1,从湖泊 i 到湖泊 i + 1 所需的 5 分钟间隔数表示为 ti (0 < ti <=192)。例如,t3 = 4 表示从湖 3 到湖 4 需要 20 分钟。为了帮助计划他的钓鱼之旅,约翰收集了一些关于湖泊的信息。对于每个湖泊i,预计在最初的5分钟内捕获的鱼的数量,记作fi(fi >= 0),是已知的。
每钓鱼 5 分钟,预计在接下来的 5 分钟间隔内捕获的鱼数量就会以恒定的 di (di >= 0) 速率减少。如果预计在一个区间内捕获的鱼的数量小于或等于di,则在下一个区间内湖中将不再有鱼。为了简化计划,约翰假设没有其他人会在湖边钓鱼,以影响他预计捕获的鱼的数量。
编写一个程序来帮助约翰计划他的钓鱼之旅,以最大限度地增加预期捕获的鱼的数量。在每个湖泊花费的分钟数必须是 5 的倍数。
三、问题分析与求解
1.1992分析与求解:
这道题是问你有多少种能最快到达终点的方法。注意这里的最快不是相对是最快。而是路线只能向右或者向下 不允许向上或者向左走。
2.1042分析与求解:
我们可以把总时间分为两个部分:在路上的时间和在钓鱼的时间。由于路是单行的,所以在路上的时间取决于走的最远距离,即到达的池塘的最大编号。 剩余的时间用于钓鱼。我们可以把移动+钓鱼的混合过程拆分为移动的过程和钓鱼的过程,即指定一个池塘为终点,移动过程即从起点到终点的过程,钓鱼的过程就是从起点到终点的各个池塘中选择池塘钓鱼,因为移动过程所需的时间已经在前面考虑过了,这个时候我们就可以认为需要移动的时候可以直接瞬间到达。然后,选择到哪些池塘钓鱼的策略采用贪心的方法,每个钓鱼的5分钟都选择期望最大的那一个池塘,每在选择一个池塘钓鱼5分钟,减少相应池塘的期望,增加计划中在该池塘钓鱼的时间,然后继续选择期望最大的池塘,直到钓鱼的时间不够,或者池塘里没有鱼了。如果池塘没有鱼了,还有时间的话,把多余的时间分配给第一个池塘。
四、AC源代码、截图
#include<stdio.h>
#include<malloc.h>
#include<string.h>
typedef struct{
int x, y;
}Point;
typedef struct{
Point Q[1100];
int top, tail;
}Que;
Que q;
void ini() {q.top = 0, q.tail = 0;}
void push(int x, int y) {q.Q[q.tail].x = x, q.Q[q.tail].y = y;q.tail++; if(q.tail > 1099) q.tail = 0;}
Point pop() {Point tt; tt = q.Q[q.top++]; if(q.top > 1099) q.top = 0; return tt;}
bool empty() {if(q.tail == q.top) return 1; return 0;}
int R, S;
bool map[1005][1005];
int f[1005][1005];
int main()
{
int Case;
int i, j;
char x;
Point tt;
while(scanf("%d", &Case) != EOF){
while(Case--){
scanf("%d%d", &R, &S);
for(i = 0; i < R; ++i)
{
getchar();
for(j = 0; j < S; ++j){
scanf("%c", &x);
map[i][j] = (x == '.'? 1 : 0);
f[i][j] = 0;
}
}
push(0, 0);f[0][0] = 1;
while(!empty())
{
tt = pop();
if(map[tt.x + 1][tt.y])
{
if(!f[tt.x + 1][tt.y]) push(tt.x + 1, tt.y);
f[tt.x + 1][tt.y] += f[tt.x][tt.y];
}
if(map[tt.x][tt.y + 1])
{
if(!f[tt.x][tt.y + 1]) push(tt.x, tt.y + 1);
f[tt.x][tt.y + 1] += f[tt.x][tt.y];
}
}
printf("Existuje %d ruznych cest.\n", f[R - 1][S - 1]);
}
}
return 0;
}
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
const int N=25;
int n,h;
int f[N],d[N],t[N];//f第一个五分钟钓的鱼量,d为每个五分钟减少的鱼量,t为i到i+1五分钟的个数
int ans;
int each[N];//记录最终每条湖用的时间
int tans,teach[N];//最优钓鱼量和各湖钓鱼时间
int th,tf[N];//有效钓鱼时间和每条湖前五分钟的钓鱼量
int main()
{
int i,j;
while(cin>>n&&n>0){//当湖的数量为0的时候结束
cin>>h;//输入时间
for(i=0;i<n;i++){
cin>>f[i];//第一次的鱼量
}
for(i=0;i<n;i++){
cin>>d[i];//每五分钟减少的鱼量
}
for(i=0;i<n-1;i++){
cin>>t[i];//每个湖间距离需要的时间片
}
h*=12;//一小时12个时间片
ans=-1;
for(i=0;i<n;i++){//表示再第i条湖停下来
//初始化每一次贪心
th=h;//有效时间先初始化为总时间
for(j=0;j<n;j++){
tf[j]=f[j];//每条湖初始的钓鱼量初始为第一次五分钟的钓鱼量
teach[j]=0;//每个湖的钓鱼时间初始化为0
}
tans=0;//最大钓鱼数初始化为0
//对每五分钟贪心选择钓鱼量最大的湖钓鱼
while(th>0){//当有效时间大于0
int ind=0,max=tf[0];//令第一条湖的鱼量为最大值 ,ind标记湖是第几条湖
for(j=0;j<=i;j++){
if(tf[j]>max){//不考虑顺序先找第一次鱼量最大的湖
max=tf[j];
ind=j;
}
}
if(max==0){//最大钓鱼量为0时,将剩余的钓鱼时间加到第一个湖上的钓鱼时间
teach[0]+=th*5;//例如样例一
break;
}
else{
teach[ind]+=5;//最大湖的钓鱼时间,每钓一次加一次五
tans+=tf[ind];//加上最大鱼量的湖的该次的鱼数
if(tf[ind]>=d[ind])//如果鱼量不少于减少的鱼数 ,则减
{
tf[ind]-=d[ind];
}
else{
tf[ind]=0;//小于减少数则赋值为0
}
}
th--;//有效时间减少一个时间片(一个时间片五分钟)
}
if(i!=n-1){//i的话是表示在第i条湖停下来
h-=t[i];//减去到下一条湖的时间片
}
if(tans>ans){//如果值大于前面的值,就把值赋给ans
ans=tans;
for(j=0;j<n;j++){
each[j]=teach[j];//记录最终每条湖用的时间
}
}
}
cout<<each[0];
for(i=1;i<n;i++){
cout<<", "<<each[i];
}
cout<<endl;
cout<<"Number of fish expected: "<<ans<<endl;
cout<<endl;
}
return 0;
}
五、实验小结
1.迷宫问题最短路径问题中,每次处理的位置所对应的距离是严格递增的,因此,一旦找到终点,当前的距离就是最短距离,
搜索可移动到的位置中,判断条件不仅仅是不碰壁不超边界,还有一个条件就是没有到达过。因为,如果已经到达了这个位置,这说明已经有更短的路径到达了这个位置,这次到达这个位置的路径是更远的,不可能达到最优解;
2.贪心算法存在的问题:
(1)不能保证求得的最后解是最佳的;
(2)不能用来求最大值或最小值的问题;
(3)只能求满足某些约束条件的可行解的范围。