DP问题转化为图论问题

小范围DP转化为图论

总结

比较经典的题型,小范围内的DP通常会转化为图论

小红不想做完全背包 (hard)

地址

对于每一个物品,可以产生 p 条路径:$0$->$a[i]$%p,$1$->$(a[i]+1)$%p$…$$p-1$->$(a[i]+p-1)$%p

然后利用 BFS 求出到 0 的最短路,每一个 a[i] 都是起始点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void solve()
{
    int n,p;
    cin>>n>>p;
    queue<int> q;
    for(int i=0;i<=p;i++) d[i]=INF;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i]%=p;     
        if(d[a[i]]!=1){
            q.push(a[i]);
            for(int j=0;j<p;j++){
                g[j].push_back((j+a[i])%p);
            }
        } 
        d[a[i]]=1;
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        for(auto v : g[u]){
            if(d[v]==INF){
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    cout<<d[0];
}

Tokitsukaze and Slash Draw

地址

同样因为取模的特性,导致点的大小范围事实上较小,可以用 DP ,同样可以转化为图论,利用最短路解决

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void solve()
{
    int n,m,k;
    cin>>n>>m>>k;
    vector<int> a(m+1),b(m+1);
    vector<int> prc(n+1,INF);
    for(int i=1;i<=m;i++){
        cin>>a[i]>>b[i];
        for(int j=1;j<=n;j++){
            prc[(a[i]*j-1)%n+1]=min(prc[(a[i]*j-1)%n+1],b[i]*j);
        }
    }
    vector<int> dp(n+1,INF);//dp[i]表示牌在从下往上数第i张时的最小代价
    dp[k]=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(prc[i]!=INF) dp[j]=min(dp[j],dp[(j-i+n-1)%n+1]+prc[i]);
        }          
    }
    cout<<(dp[n]==INF ? -1 : dp[n])<<"\n";
}
Licensed under CC BY-NC-SA 4.0
最后更新于 Apr 12, 2024 00:00 UTC
本博客已稳定运行
使用 Hugo 构建
主题 StackJimmy 设计