挖宝藏
treasures/.in/.out/.pas/.exe
【题意】
在一个无限大的二维网格中有n处宝藏,给出每个宝藏的坐标(x[i],y[i])以及价值p[i],已知挖掘一个网格(x,y)需要满足<该点纵坐标y=-1>或<(x-1,y+1)(x,y+1)(x+1,y+1)三个网格都被挖掘过>,挖掘一个网格需要1代价,挖掘有宝藏的网格则可得到该宝藏的价值,求最大收益
【输入】
第一行一个数字n(n<=1000)
接下来n行每行三个数字表示一个宝藏(每个宝藏的横坐标大于等于-10000小于等于10000,纵坐标小于等于-1,价值不超过大于等于1小于等于1000000)
【输出】
输出一个数表示最大收益
动态规划
首先说一个思路上的误区,我看到这道题发现要挖掘一个点需要挖掘它之下的一个三角形,首先想到的是一行一行的处理,这不科学。
这道题应当竖着一列一列的处理,f[x][y]表示处理到第x行,最低点在y的最大收益
那么f[x][y]=max(f[x-1][y-1],f[x-1][y],f[x-1][y+1])+p[x][y] (p[x][y]表示第p列在-1..y的所有宝藏价值及挖掘费用之差)
由于x范围为20000,y范围为10000,20000*10000=200000000,时间上不允许
由于点比较少,所以采取离散化
首先枚举x坐标,然后求出在该列上的三角形边界上的点的纵坐标,排序后求p,便可以dp了
n<=1000的,相比于y优化了10倍,便可在规定时限内通过所有数据
program treasures; type point=record x,y,p:longint; end; arr=array [-10001..0] of longint; var tot,n,i,j,k,s,e,o,sum:longint; dl,root:array [0..1001] of point; zero:arr; f:array [0..1] of arr; procedure swap (var a,b:longint);inline; var i:longint; begin i:=a; a:=b; b:=i; end; procedure qsort (s,e:longint); var i,j,k:longint; begin if s>=e then exit; i:=s; j:=e; k:=dl[(s+e) div 2].y; while i<=j do begin while dl[i].y>k do inc(i); while dl[j].y<k do dec(j); if i>j then break; swap(dl[i].x,dl[j].x); swap(dl[i].y,dl[j].y); swap(dl[i].p,dl[j].p); inc(i); dec(j); end; qsort(s,j); qsort(i,e); end; begin assign(input,'treasures.in'); reset(input); assign(output,'treasures.out'); rewrite(output); read(n); s:=maxlongint; e:=-maxlongint; for i:=1 to n do begin read(root[i].x,root[i].y,root[i].p); if root[i].x+(root[i].y+1)<s then s:=root[i].x+(root[i].y+1); if root[i].x-(root[i].y+1)>e then e:=root[i].x-(root[i].y+1); end; for i:=-10000 to 0 do zero[i]:=-maxlongint div 10; zero[0]:=0; o:=0; f[o]:=zero; tot:=0; for i:=s to e+1 do begin o:=1-o; f[o]:=zero; tot:=0; for j:=1 to n do if (root[j].x+(root[j].y+1)<=i) and(root[j].x-(root[j].y+1)>=i) then begin inc(tot); dl[tot].x:=i; dl[tot].y:=root[j].y+abs(root[j].x-i); if root[j].x=i then dl[tot].p:=root[j].p else dl[tot].p:=0; end; qsort(1,tot); f[o,0]:=f[1-o,0]; if f[1-o,-1]>f[o,0] then f[o,0]:=f[1-o,-1]; k:=0; sum:=0; for j:=1 to tot do begin sum:=sum+dl[j].p+dl[j].y-k; k:=dl[j].y; if f[o,dl[j].y]<f[1-o,dl[j].y-1]+sum then f[o,dl[j].y]:=f[1-o,dl[j].y-1]+sum; if f[o,dl[j].y]<f[1-o,dl[j].y]+sum then f[o,dl[j].y]:=f[1-o,dl[j].y]+sum; if f[o,dl[j].y]<f[1-o,dl[j].y+1]+sum then f[o,dl[j].y]:=f[1-o,dl[j].y+1]+sum; end; end; writeln(f[o,0]); close(input); close(output); end.