香穗子在田野上调蘑菇!她跳啊跳,发现自己很无聊,于是她想了一个有趣的事情,每个格子最多只能经过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’]),由于找不到递推顺序,所以用记忆化搜索的方式求解,对每个点进行一次搜索,输出最大值即可
提交情况:显然1次AC
经验:不要尝试去找这种类型的方程的递推顺序= =
收获:同上
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的可以蹲墙角了……
提交情况:1次AC
经验:无
收获:练打字吧……
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,要么都不能互相到达,一定不存在A和B都能互相到达.
现在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……
提交情况:第一次DP,4组TLE,第二次SPFA,AC。
经验:有向有环图……不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<=100,m<=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-1和i-k两个点上,另外,DP时注意几点:1、初值,2、I,j大小关系,3,j=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.