[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;   
}

猜你喜欢

转载自www.cnblogs.com/tqr06/p/11622865.html