AcWing 187. 导弹防御系统 (dfs,贪心,LIS)
-
题意:给你一组数,问你最少能凑多少个LIS和LDS.
-
题解:能解决的办法好像只有dfs找了,但是我们可以贪心和剪枝来优化,我们来看贪心,当我们遍历到\(i\)个数时,想要把它加入到前面的某个上升子序列中,那么最优的放法一定是放到末尾数字比\(a[i]\)小的最大的那个数后面,因为加入放到一个末尾数字很小的子序列后面,肯定是浪费的.然后照这个贪心思路就可以dfs了.
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n; int a[N]; int up[N],down[N]; int ans; //pos表示当前位置,u表示当前上升序列的个数,d表示当前下降序列的个数 void dfs(int pos,int u,int d){ if(u+d>=ans) return; //剪枝 if(pos==n){ ans=u+d; return; } int k; //找到第一个末尾比当前位置小的上升序列,如果没有就新建一个新的上升序列 //这里一定保证第一个满足条件的是最优的(即末尾最大),因为第x+1个序列的末尾一定比第x个小 //自己可以写几个例子看看 for(k=1;k<=u;++k) if(up[k]<a[pos]) break; int tmp=up[k]; up[k]=a[pos]; dfs(pos+1,max(u,k),d); up[k]=tmp; //dfs回溯,不再赘述 for(k=1;k<=d;++k) if(down[k]>a[pos]) break; tmp=down[k]; down[k]=a[pos]; dfs(pos+1,u,max(d,k)); down[k]=tmp; } int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); while(cin>>n,n!=0){ rep(i,1,n){ cin>>a[i]; } ans=n; dfs(1,0,0); cout<<ans<<'\n'; } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮