有一个 n 层的数字三角形
每次可以从第 i 层的第 j 个走到第 i + 1 层的第 j 个或是第 j +1 个,直到走到第 n 层
从第 1 层走到第 n 层的一种方案成为一条路径,路径的权值为路径上点权值之和
求权值前 k 大的路径(存在多个正确答案)
20分做法:
枚举二进制串,暴力枚举所有走法
复杂度:(Theta(2^n))
60分做法:
对每个点开一个堆,维护从下往上的前k大值,由于只和下一层有关,可以滚动
复杂度:(Theta(n^3log{(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;
}