【水】【动态规划】香穗子系列解题报告

本文介绍了香穗子在不同场景下解决数学问题的过程,包括动态规划问题、物品选择优化以及路径规划。通过举例和分析,展示了如何利用动态规划、最长上升子序列等算法解决问题,并分享了编程技巧和经验总结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 1  活蹦乱跳的香穗子

香穗子在田野上调蘑菇!她跳啊跳,发现自己很无聊,于是她想了一个有趣的事情,每个格子最多只能经过1,且每个格子都有其价值

跳的规则是这样的,香穗子可以向上下左右四个方向跳到相邻的格子,并且她只能往价值更高(这里是严格的大于)的格子跳.

香穗子可以从任意的格子出发,在任意的格子结束,

那么她最多能跳几次?

输入:

       第一行n,m,表示田野的长和宽

接下来n,每行m个数,表示该格的价值

输出:

一个数,表示最多跳得次数

Sample Input

2 2

2 5

-1 3

 

Sample Output

       3

 

数据范围:

       n,m<=100

       答案保正小于Maxlongint

 

思路:目测和滑雪一样,最长上升子序列升级版,显然,每个点的值由周围四个点可以推出,易得方程:f[I,j]=max{f[i-1,j],f[i+1,j],f[I,j-1],f[I,j+1]}+1 (map[I,j]<map[I’,j’]),由于找不到递推顺序,所以用记忆化搜索的方式求解,对每个点进行一次搜索,输出最大值即可

提交情况:显然1AC

经验:不要尝试去找这种类型的方程的递推顺序= =

收获:同上

 

ACCode

Program one;

Const

       xc:array[1..4]oflongint=(0,1,0,-1);

       yc:array[1..4]oflongint=(1,0,-1,0);

Var

       n,m,max:longint;

       map,f:array[0..150,0..150]oflongint;

Procedure init;

var

       i,j:longint;

begin

       assign(input,'1.in');

       assign(output,'1.out');

       reset(input);

       rewrite(output);

 

       readln(n,m);

       fori:=1 to n do

              forj:=1 to m do

                     read(map[i,j]);

end;

 

Procedure terminate;

begin

       close(input);

       close(output);

       halt;

end;

 

Function dp(x,y:longint):longint;

var

       i,t:longint;

begin

       iff[x,y]<>0 then exit(f[x,y]);

       

       fori:=1 to 4 do

       begin

              if(x+xc[i]<0)or(x+xc[i]>n)or(y+yc[i]<0)or(y+yc[i]>n) then continue;

              ifmap[x+xc[i],y+yc[i]]<=map[x,y] then continue;

              t:=dp(x+xc[i],y+yc[i]);

              ift+1>f[x,y] then f[x,y]:=t+1;

       end;

              

       exit(f[x,y]);

end;

 

Procedure main;

var

       i,j,x:longint;

begin

       max:=0;

       fori:=1 to n do

              forj:=1 to n do

              begin

                     x:=dp(i,j);

                     ifx>max then max:=x;

              end;

 

       writeln(max+1);

end;

 

Begin

       init;

       main;

       terminate;

End.

 

Problem 2 可爱迷人的香穗子

  香穗子正准备参加一个晚会!现在她准备好好打扮一下,她准备戴上耳环,手镯,项链..等等一些装饰品,这里要说明的是,香穗子不是花瓶….

  香穗子最多能承受W的重量,每个装饰品也有各自的重量和美观值

  现在香穗子要怎么打扮,美观值的和最大

 

输入:

       第一行两个数,w,n

       接下来n,每行两个数,表示物品的信息,第一个数是物品的重量,第二个数是物品的美观值

 

输出:

       表示香穗子最多能得到的最大美观值和

 

Sample Input

       10 2

       7 8

       8 7

 

Sample Output

       8

 

数据范围:

       n<=100,w<=10000

       答案保正小于Maxlongint

 

思路:目测可知,此题为裸01背包……方程神马的不用说了吧……01背包不能直接AC的可以蹲墙角了……

提交情况:1AC

经验:无

收获:练打字吧……

 

ACCode

Program two;

Var

       f:array[0..150,0..10050]oflongint;

       w,v:array[0..150]oflongint;

       n,wei,max,i,j:longint;

Begin

       assign(input,'2.in');

       assign(output,'2.out');

       reset(input);

       rewrite(output);

       

       readln(wei,n);

 

       fori:=1 to n do

              readln(w[i],v[i]);

       max:=0;

       f[1,w[1]]:=v[1];

       fori:=2 to n do

              forj:=1 to wei do

              begin

                     if(j-w[i]>0)and(f[i,j]<f[i-1,j-w[i]]+v[i]) then f[i,j]:=f[i-1,j-w[i]]+v[i];

                     if(f[i,j]<f[i-1,j]) then f[i,j]:=f[i-1,j];

                     iff[i,j]>max then max:=f[i,j];

              end;

       

       writeln(max);

 

       close(input);

       close(output);

End.


 

Problem 3 Cyh和香穗子

  话说,Cyh和香穗子是好朋友,一天他们在fzsz迷路了….Cyh在地点1,香穗子在地点n.由于Cyh是土生土长的fzsz,所以Cyh准备去n地给香穗子带路.

fzsz是个奇怪的地方,它由n地点组成,并且任意两个地点A,B满足要么A能到B,要么B能到A,要么都不能互相到达,一定不存在AB都能互相到达.

  现在Cyh希望快点到达n

 

输入:

       第一行两个数n,m

       接下来m,每行两个数a,b,表示地点a能达到地点b

 

输出:

       Cyh最少经过的地点数

 

Sample Input

       4 5

       1 2

       2 3

       2 4

       1 3

       3 4

 

Sample Output

       3

 

数据范围:

       n<=100000,m<=500000,保正有解

 

 

思路:MD……坑爹啊……此题可能出现有向有环图。所以在DP之前需要先Tarjan缩点。不过鉴于这是套水题,所以可耻地用了SPFA……

提交情况:第一次DP4TLE,第二次SPFAAC

经验:有向有环图……不Tarjan的话DP个毛啊……

收获:踩了一个坑

 

ACCode

Program three;

Type

       what=^node;

       node=record

              n:longint;

              next:what;

       end;

Var

       head:array[1..100000]of what;

       dis:array[1..100000]of longint;

       list:array[0..500000]of longint;

       boo:array[1..100000]of boolean;

       m,n:longint;

 

Procedure insert(x,y:longint);

var

       p:what;

begin

       new(p);

       p^.n:=y;

       p^.next:=head[x];

       head[x]:=p;

end;

 

procedure init;

var

       i,x,y:longint;

begin

       assign(input,'3.in');

       assign(output,'3.out');

       reset(input);

       rewrite(output);

       

       read(n,m);

       fori:=1 to m do

              begin

              read(x,y);

              insert(x,y);

       end;

end;

 

Procedure terminate;

begin

       close(input);

       close(output);

       halt;

end;

 

Procedure main;

var

       l,r,now,i:longint;

       p:what;

begin

       dis[1]:=1;

       fori:=2 to n do 

              dis[i]:=10000000;

 

       l:=0;

       r:=1;

       list[r]:=1;

       boo[1]:=true;

       whilel<>r do

       begin

              l:=(l+1)mod 500000;

              now:=list[l];boo[now]:=false;

 

              p:=head[now];

              whilep<>nil do

              begin

                     ifdis[p^.n]>dis[now]+1 then

                     begin

                            dis[p^.n]:=dis[now]+1;

      

                            ifnot boo[p^.n] then

                            begin

                                   r:=(r+1)mod 500000;

                                   list[r]:=p^.n;

                                   boo[p^.n]:=true;

                            end;

                     end;

                     p:=p^.next;

              end;

       end;

 

       writeln(dis[n]);

end;

 

begin

 init;

 main;

 terminate;

end.

 

Problem 4 聪明伶俐的香穗子

  香穗子遇到难题了.

  题目是这样的,一个序列上有n个整数,现在你要取m,且这m个数的任意两个不能相隔的太近,否则这样会太丑,现在问你最大能得到多大的和

 

输入:

       第一行三个数n,m,k,分别表示n个数,m,m个中的任意两个位置差要大于等于K

       接下来一行,n个整数,表示序列上的每个数

 

输出:

       最大和

 

Sample Input

       4 2 2

       3 4 -5 1

 

Sample Output

       5

 

数据范围:

       n<=10000,m<=100m<=n

       答案保正小于Maxlongint

 

思路:显然,一道水DP,设计状态:f[I,j]表示前i个数,取j个,所能得到的最大和,则有f[I,j]=max{f[i-1,j],f[i-k,j-1]}(即第i个数取或者不取),递推即可,那些方程比较菜,用数据结构优化的都菜!

提交情况:还是初值问题,因为这题有点奇葩,WA1次,然后AC

经验:没有必要枚举i之前的所有点,因为前面所有的点一定会转移到i-1i-k两个点上,另外,DP时注意几点:1、初值,2I,j大小关系,3j=1的情况比较特殊

 

ACCode

 

Program four;

uses math;

Var

       a:array[0..10050]oflongint;

       f:array[-500..10050,0..100]oflongint;

       n,m,k:longint;

 

Procedure init;

var

       i:longint;

begin

       assign(input,'4.in');

       assign(output,'4.out');

       reset(input);

       rewrite(output);

 

       fillchar(f,sizeof(f),-$3f);

 

       readln(n,m,k);

       fori:=1 to n do

       begin

              read(a[i]);

       end;

end;

 

Procedure terminate;

begin

       close(input);

       close(output);

       halt;

end;

 

Procedure main;

var

       i,j:longint;

begin

       f[1,1]:=a[1];

       

       f[1,0]:=-$3f3f3f3f;

       fori:=2 to n do

              f[i,1]:=max(a[i],f[i-1,1]);

       fori:=2 to n do

              forj:=2 to m do

              begin

                     ifi>=(j-1)*k+1 then 

                     f[i,j]:=max(f[i-1,j],f[i-k,j-1]+a[i]);

              end;

                            

       writeln(f[n,m]);

end;

 

Begin

       init;

       main;

       terminate;

End.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值