[ACM_动态规划] Alignment (将军排队)
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28415#problem/F
题目大意:有n个士兵排成一列,将军想从中抽出最少人数使队伍中任何士兵都能够看到左边最远处或右边最远处 |
解题思路:①此题是最长上升子序列的升级版。 ②这里先介绍一下最长上升子问题(LIS):给定n个数从右往左选出尽量多的数,组成一个上升子序 列,相邻的不能相等 ——> 设d[i]表示以第i个数结尾的最长上升子序列,则状态转移方程为:d[i]= max{0,d[j]|j<i,a[j]<a[i]},答案是max{d[i]}; ③此题可从左往右求出d[](代码里为b[]),再从右往左求出d[](代码里为c[]),答案就是max{b[i]+c[j] | i<j} |
#include<iostream> #include<cmath> #include<string> #include<algorithm> using namespace std; int main(){ double a[1005]; int b[1005],c[1005]; for(int n;cin>>n&&n;){ for(int i=0;i<n;i++){ //输入身高数据a[]并正向计算以第i个结尾的LIS对应为b[i] cin>>a[i]; int max=-1; for(int j=0;j<i;j++){ if(a[i]>a[j]&&b[j]>max){ max=b[j]; } } if(max==-1)b[i]=1; else b[i]=max+1; } for(int i=n-1;i>=0;i--){ //逆向计算以第i个结尾的LIS对应为c[i] int max=-1; for(int j=n-1;j>i;j--){ if(a[i]>a[j]&&c[j]>max){ max=c[j]; } } if(max==-1)c[i]=1; else c[i]=max+1; } double maxtotal=-1; //计算b[i]+c[j] && i<j 的最大值 for(int i=0;i<n;i++){ for(int j=n-1;j>i;j--){ int sum=b[i]+c[j]; if(sum>maxtotal){ maxtotal=sum; } } } cout<<n-maxtotal<<'\n'; //输出挑出的最少人数 }return 0; }
|