【动态规划】【poj 1836】Alignment
问题
有一列士兵排队,给出其身高a[i],现在要让队列中的一些士兵出列,使得剩下的每个士兵都能够看到对头或队尾(在该士兵和他看到的队尾之间没有比该士兵高的士兵)。现在要求最少的出对的士兵数。
分析
乍一看很像最长xx序列,但是又没有思路,需要抽象题目中的模型。假设a[i]是满足要求的队列中的元素,那么假设a[1]是左边的对首,a[1]~a[i]中的元素都比a[i]小,也就是说a[1]~a[i]的元素都可以满足要求。那么在a[i]的右边的元素只可能比a[i]大或者小,如果比a[i]小,那么从该元素一直到队尾一定是递减的,才能满足题目要求。
这样一来,问题就转化成:在队列a[i]中找到一个元素,使得a[1]<a[2]<a[3]<……a[i]>a[i+1]>a[i+2]…..>a[n]即可。这样就很像合唱队形问题,只需要两遍最长上升序列即可,然后枚举最值。但是还有一种特殊情况要考虑,就是最高的元素可能是两个即a[1]<a[2]<a[3]<……a[i]=[i+1]>a[i+2]…..>a[n]当然只有两个时是满足题意的(一旦三个同样高,中间的就会被两边的挡住)。这样一来问题就解决了。
code
program liukee; var f1,f2:array[0..1000] of longint; a:array[0..1000] of double; i,j,n,ans:longint; function max(a,b:longint):longint; begin if a>b then exit(a) else exit(b); end; begin readln(n); for i:=1 to n do read(a[i]); for i:=1 to n do begin f1[i]:=1; f2[i]:=1; end; for i:=1 to n do for j:=i-1 downto 1 do if a[j]<a[i] then f1[i]:=max(f1[i],f1[j]+1); for i:=n downto 1 do for j:=i+1 to n do if a[j]<a[i] then f2[i]:=max(f2[i],f2[j]+1); for i:=1 to n do begin ans:=max(ans,f1[i]+f2[i]-1); for j:=i+1 to n do if a[i]=a[j] then ans:=max(ans,f1[i]+f2[j]); end; writeln(n-ans); end.
反思
想到了基本模型,但没有抽象成正确解。没有考虑特殊情况。
遇到熟悉的提醒要先考虑共性,再按照题目要求完成问题的转化。最后要考虑题目的特殊性。