记忆化搜索Presents in Bankopolis(CF793D )

先是流水账

报名了camp的div1,原本说是cf能1500以上就div1来着?但是这每日一题感觉都不是很友好,每天会花很长时间去做,而且理解还不深刻,但是既然已经做了,怎么能白白花费时间呢,所以还是要写个题解记录一下。

题解

题意:
给定一个有向有权图(图中会有重边,环)。对于每个节点都有自己的编号,询问一条包含k个节点路径的最小权值,并且有特殊要求如下:对于将行路径x—>y没有已经走过的节点编号 t 满足:min(x,y)=<t<=max(x,y)

分析:
1.根据题目数据范围,我们可以采用vector或者邻接矩阵存储图。
2.对于题目的特殊要求min(x,y)=<t<=max(x,y),翻译过来就是,x向下走到y,对y必须有在之前走过的区间之内,1 2 6 7是不合法的路径,因为走7时越过了已经走过的节点6(可以用数轴表示能看的直观一些)
3.根据2可知每一次走完可走区间都会缩小,并且小区间不会影响大区间,根据这两点特性可以锁定是区间DP做法,也可用不断缩小上下界的BFS来做。

下为记忆化搜索代码,建议从main函数开始看

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int>p;
vector<p> v[105];
int dp[110][110][110][110];//利用四个维度来表示:可行区间为l到r,目前决策点为第三维度表示,第四维度表示目前记录了多少路径
int n,m,k;
int DFS(int x,int y,int u,int cnt)
{
    if(cnt==k)//路径记录终了
        return 0;
    if(dp[x][y][u][cnt])//已经搜过的情况立即返回即可
        return dp[x][y][u][cnt];
    int &res=dp[x][y][u][cnt];
    res=1e9;
    for(auto f:v[u])//遍历u所连接的节点
    {
        if(f.first<y&&f.first>x&&f.first!=u)
        {
            if(u>f.first)
            res=min(res,f.second+DFS(x,u,f.first,cnt+1));
            else
            res=min(res,f.second+DFS(u,y,f.first,cnt+1));
        }
    }
    return res;
}
int main()
{
    cin>>n>>k>>m;
    for(int i=1,u,r,w;i<=m;i++)
    {
        scanf("%d%d%d",&u,&r,&w);
        v[u].push_back(p(r,w));
    }
    int ans=1e9;
    for(int i=1;i<=n;i++)
    {
        ans=min(ans,DFS(0,n+1,i,1));
    }
    if(ans==1e9)
        cout<<-1<<endl;
    else
        cout<<ans<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值