CodeForces - 793D DP+dfs

16 篇文章 0 订阅

最近做DP做得有点多。。技巧和思路是提升了不少。但是还是会忽略不少细节,特别是dfs+dp的题目上。比如说这题,就出现了两个足以让人窒息的错误:1、数组d的值可能会是我初始化的负数,所以返回再求最小,必然是输出-1,所以需要在末尾加上一个判断它的正负。2、第二个就是数组下标的越界的导致的re问题,要时刻注意数组的下标是否可以取得到,特别是未初始化的值做下表时。


思路:这道题开始简单地以为是DAG上的DP,后来打的时候发现,这个又要复杂一点。思路也是参考网上的。。。

题目给出了n个节点,以及一组路径,问:经过k个点的最短距离是多少,要求下一次走的路径不能完全覆盖上一次的路径。

首先n个节点可以看做是对应数轴上的点,每次走一段路径后,就要更新下次的合法距离。开始的合法距离注意要是0~n+1。

分三种情况讨论:

1、如果下次进入的点在合法距离以外则舍弃掉该点。

2、如果在合法距离内:a、大于当前位置,则合法距离的左边界应为当前位置。b、小于当前位置,则合法距离的右边界应为当前位置。具体可以画图理解。

然后就是dfs每个节点,找出所有情况了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=82;
int n,m,k,w,G[maxn][maxn],d[maxn][maxn][maxn][maxn],st,en,mins,ans;//d[l][r][st][k];从第

int dfs(int st,int step,int l,int r){//从st出发,剩余step步,范围为l r的最短步长
    if(d[l][r][st][step]!=-1)
        return d[l][r][st][step];///已经得出来答案就不需要再进行
    if(step==1){
       return d[l][r][st][step]=0;///递归走到第一步
    }
    for(int i=1;i<=n;i++){///递归st的所有儿子
        if(G[st][i]!=inf&&i>l&&i<r){
            int l1=l,r1=r;
            if(i>st)
                l1=st;
            else
                r1=st;
            int ans=dfs(i,step-1,l1,r1);
            if(d[l][r][st][step]>0){
              d[l][r][st][step]=min(ans+G[st][i],d[l][r][st][step]);
            }
            else
              d[l][r][st][step]=ans+G[st][i];
        }
    }
    if(d[l][r][st][step]>0)
    return d[l][r][st][step];
    return inf;
}

int main(){
    while(cin>>n>>k>>m){
        memset(d,-1,sizeof(d));
        memset(G,inf,sizeof(G));
        mins=inf;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&st,&en,&w);
            G[st][en]=min(G[st][en],w);///考虑有重边的情况
        }
        for(int i=1;i<=n;i++){
            mins=min(mins,dfs(i,k,0,n+1));
        }
        if(mins>=inf)
            mins=-1;
            printf("%d\n",mins);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值