Live2D

[20191004机房测试] 三角

有一个 n 层的数字三角形
每次可以从第 i 层的第 j 个走到第 i + 1 层的第 j 个或是第 j +1 个,直到走到第 n 层
从第 1 层走到第 n 层的一种方案成为一条路径,路径的权值为路径上点权值之和
求权值前 k 大的路径(存在多个正确答案)

20分做法:
枚举二进制串,暴力枚举所有走法
复杂度:\(\Theta(2^n)\)

60分做法:
对每个点开一个堆,维护从下往上的前k大值,由于只和下一层有关,可以滚动
复杂度:\(\Theta(n^3\log{(n)})\)

100分做法:
可以看作IDA*,本质是有限制性的搜索
对每个第k大的值二分答案,看其能否被组合出来
然后搜索就行
复杂度:搜索剪枝的复杂度都很玄学

代码:

#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;

int n,k,a[1005][1005],f[1005][1005],way[1005],cnt;
bool output;

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

void dfs(int x,int y,int now,int lim)
{
	if(cnt>=k) return;
	if(now+f[x][y]<lim) return;
	if(x==n+1)
	{
		++cnt;	
		if(output)
		{
			for(register int i = 1; i < n; ++i)
				printf(way[i]==1?"R":"L");
			puts("");
		}
		return;
	}
	way[x]=0;
	dfs(x+1,y,now+a[x][y],lim);
	way[x]=1;
	dfs(x+1,y+1,now+a[x][y],lim);
}

int main()
{
	freopen("tri.in","r",stdin);
	freopen("tri.out","w",stdout);
	read(n);read(k);
	for(register int i=1;i<=n;++i)
		for(register int j=1;j<=i;++j)
			read(a[i][j]),f[i][j]=a[i][j];
	for(register int i=n-1;i>=1;--i)
		for(register int j=1;j<=i;++j)
			f[i][j]=a[i][j]+max(f[i+1][j],f[i+1][j+1]);
	int l=0,r=1000005,ans;
	while(l<=r)
	{
		cnt=0;	
		dfs(1,1,0,mid);
		if(cnt>=k)
			l=mid+1,ans=mid;
		else r=mid-1;
	}
	cnt=0;
	output=1;
	dfs(1,1,0,ans);	
	return 0;	
}
posted @ 2019-10-04 19:00  tqr06  阅读(200)  评论(0编辑  收藏  举报