1. 程式人生 > 其它 >洛谷P4802 [CCO 2015]路短最

洛谷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;
}