1.迭代加深+贪心

niteko 2020-07-28 10:42:48 2020-07-28 14:30:37

!^{!^{!^{!^{!^{!^{!^{!^{!^{!}}}}}}}}}

1. 迭代加深+贪心 O(n*2^n)

#include <cstdio>
const int N = 66;

using namespace std;

int n, ans, a[N], up[N], down[N];
//ans枚举depth
//up[i]和down[i]分别储存第i个上升子序列和下降子序列的最后一个数

bool dfs (int dep, int cur, int uu, int dd)
//cur为当前需要拦截的导弹的编号
//uu和dd分别是当前上升子序列和下降子序列的个数
{
	if (uu + dd > dep) return 0;  //超出深度就返回
	if (cur == n) return 1;   //数组从0开始使用, 所以到n就返回

     //接下来分别试探当前导弹能否被已知系统拦截
     //对于上升子序列而言(下降子序列类似),将当前数接在最大的数后面,一定不会比接在其他数列后面更差。
     //这是因为处理完当前数后,一定会出现一个以当前数结尾的子序列,这是固定不变的,那么此时其他子序列的末尾数越小越好。
     //按照这种贪心思路,up[]和down[]一定是单调的,因此在遍历时找到第一个满足的序列后就可以直接break了
	
	bool ok = 0;//记录是否成功
	for (int i = 1; i <= uu; i++)
	{
		if (up[i] < a[cur])
		{
			int b = up[i]; //备份当前up[i]
			up[i] = a[cur];
			if (dfs(dep, cur+1, uu, dd)) return 1; //dfs下一层
			ok = 1;
			up[i] = b; //还原
			break;
		}
	}
    if (!ok) {
        up[uu + 1] = a[cur];
        if (dfs(dep, cur + 1, uu + 1, dd))
            return 1;
    }
	
	ok = 0; //下降的进行同上
	for (int i = 1; i <= dd; i++)
	{
		if (down[i] > a[cur])
		{
			int b = down[i];
			down[i] = a[cur];
			if (dfs(dep, cur+1, uu, dd)) return 1;
			ok = 1;
			down[i] = b;
			break;
		}
	}
	if (!ok)
	{
		down[dd+1] = a[cur];
		if (dfs(dep, cur+1, uu, dd+1)) return 1; 
	}
	return 0;
}

int main()
{
	while (scanf("%d",&n) && n)
	{
		ans = 0;
		for (int i = 0; i < n; i++) scanf("%d",&a[i]);
		while(!dfs(ans,0,0,0)) ans++; //迭代加深
		printf("%d\n",ans);
	}
	return 0;
}

共 2 条回复

freshman7889456

tql%%%

style

tql_{tql^{tql}}