洛谷P4802 [CCO 2015]路短最

题目

https://www.luogu.com.cn/problem/P4802

思路

数据范围 \(n\leq 18\),义眼丁真,鉴定为状压。

好,那我们来思考一下状态的构建。其实是很套路的东西,我们用 \(dp[x][state]\) 表示当前在 \(x\) 点,已经走过的点的集合为 \(state\) 的答案。

然后写个记搜就完了。

比较有意思的一点是最长路的终点是钦定好的,我第一次做的时候没考虑这个WA了一大片。比较好想的一个想法是搜的时候判一下如果当前点没有出边且不等于n-1的时候返回-inf。

但是这个写法感觉比较丑。

我想了一个自认为比较妙的处理方法:建图的时候加一条从n-1到新点n的单向边,长度为1000000(或者任意一个很大的数)。这样就基本不用改之前的记搜代码了。

最终的ans减去这个大数就是答案。因为这条大边在dp时是必定选到的,所以就保证了走到n-1点。

不得不说还是切水题比较快乐,Ynoi毒瘤,lxl毒瘤

代码

点击查看代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int fst[20],nxt[500],to[500],w[500],cnt=0;
int n,m;
int dp[20][1<<18];
void add(int x,int y,int z){
    to[++cnt]=y;
    w[cnt]=z;
    nxt[cnt]=fst[x];
    fst[x]=cnt;
}
int dfs(int x,int st){
    int i;
    if(dp[x][st]) return dp[x][st];
    if(x==n) return 0;
    for(i=fst[x];i;i=nxt[i]){
        if(st&(1<<to[i])) continue;
        dp[x][st]=max(dp[x][st],w[i]+dfs(to[i],st|1<<x));
    }
    return dp[x][st];
}
int main(){
    int i,j;
    int x,y,z;
    int ans;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    add(n-1,n,inf/4);
    ans=dfs(0,0);
    printf("%d",ans-inf/4);
    // system("pause");
    return 0;
}
posted @ 2022-04-21 11:58  文艺平衡树  阅读(29)  评论(0编辑  收藏  举报