• 紫书 动态规划例题


    https://vjudge.net/contest/176767#overview

    A - A Spy in the Metro

    #include <bits/stdc++.h>  
    using namespace std;  
    const int N = 55, M = 205;  
    int t[N], d[N][M];  //j时刻在i号车站剩下的最小总等待时间  
    bool l[N][M], r[N][M];  //j时刻在i号车站是否有往左(右)的车  
      
    int main()  
    {  
        int n, m, ti, cur, cas = 0;  
      
        while(~scanf("%d", &n), n)  
        {  
            scanf("%d", &ti);  
            memset(l, 0, sizeof(l)), memset(r, 0, sizeof(r));  
            for(int i = 1; i < n; ++i) scanf("%d", &t[i]);  
      
            scanf("%d", &m);  //cur时刻车站j是否有往右的车  
            for(int i = 1; i <= m; ++i)  
            {  
                scanf("%d", &cur);  
                for(int j = 1; j <= n; ++j)  
                    r[j][cur] = 1, cur += t[j];  
            }  
            scanf("%d", &m);  //cur时刻车站j是否有往左的车  
            for(int i = 1; i <= m; ++i)  
            {  
                scanf("%d", &cur);  
                for(int j = n; j >= 1; --j)  
                    l[j][cur] = 1, cur += t[j - 1];  
            }  
      
            memset(d, 0x3f, sizeof(d));  
            d[n][ti] = 0;  
            for(int j = ti - 1; j >= 0; --j)  
            {  
                for(int i = 1; i <= n; ++i)  
                {  
                    d[i][j] = d[i][j + 1] + 1;   //在i车站等1单位时间  
                    if(l[i][j]) d[i][j] = min(d[i][j], d[i - 1][j + t[i - 1]]);  //往左  
                    if(r[i][j]) d[i][j] = min(d[i][j], d[i + 1][j + t[i]]);  //往右  
                }  
            }  
      
            printf("Case Number %d: ", ++cas);  
            if(d[1][0] > ti) puts("impossible");  
            else printf("%d
    ", d[1][0]);  
        }  
        return 0;  
    }  

    最长递增子序列变形

    C

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    #define MAXN  1009
    #define L 31
    #define INF 1000000009
    #define eps 0.00000001
    
    int n;
    double dp[MAXN][MAXN];
    double dist[MAXN][MAXN];
    struct node
    {
        double x, y;
    }a[MAXN];
    double D(const node & a, const node &b)
    {
        return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
    }
    int main()
    {
        while (scanf("%d", &n) != EOF)
        {
            for (int i = 1; i <= n; i++)
            {
                scanf("%lf%lf", &a[i].x, &a[i].y);
                for (int j = 1; j < i; j++)
                    dist[i][j] = D(a[i], a[j]);
            }
            for (int i = n - 1; i >= 2; i--)
            {
                for (int j = 1; j < i; j++)
                {
                    if (i == n - 1) dp[i][j] = dist[n][i] + dist[n][j];
                    else dp[i][j] = min(dp[i + 1][j] + dist[i + 1][i], dp[i + 1][i] + dist[i + 1][j]);
                }
            }
            printf("%.2lf
    ", dist[2][1] + dp[2][1]);
        }
    }

    D

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    #define MAXN  1009
    #define L 31
    #define INF 1000000009
    #define eps 0.00000001
    
    /*
    单向TSP 书上给的是反向DP 这样更好输出解
    */
    int n, m;
    int a[11][MAXN], dp[11][MAXN], path[11][MAXN];
    int main()
    {
        while (scanf("%d%d", &m, &n) != EOF)//m行n 列
        {
            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    scanf("%d", &a[i][j]);
                }
            }
            int ans = INF, first = 0;
            for (int j = n - 1; j >= 0; j--)
            {
                for (int i = 0; i < m; i++)
                {
                    if (j == n - 1) dp[i][j] = a[i][j];
                    else
                    {
                        int row[3] = { i + 1,i - 1,i };
                        if (i == 0)    row[1] = m - 1;
                        if (i == m - 1)    row[0] = 0;
                        sort(row, row + 3);
                        dp[i][j] = INF;
                        for (int k = 0; k < 3; k++)
                        {
                            int v = dp[row[k]][j + 1] + a[i][j];
                            if (v < dp[i][j])
                            {
                                dp[i][j] = v, path[i][j] = row[k];
                            }
                        }
                    }
                    if (j == 0 && dp[i][0] < ans)
                    {
                        ans = dp[i][0], first = i;
                    }
                }
            }
            printf("%d", first + 1);
            for (int i = path[first][0], j = 1; j < n; i = path[i][j], j++)
            {
                printf(" %d", i + 1);
            }
            printf("
    %d
    ", ans);
        }
    }

    E

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    #define MAXN  1009
    #define L 31
    #define INF 1000000009
    #define eps 0.00000001
    /*
    对于某一种灯泡 要么全部替换 要么全都不替换
    证明:如果替换N个剩下M个能带来 P*N的收益,那么替换剩下的M个可以带来P*M+K的收益。K是节约掉的搭建电源的收益
    dp[i]表示满足前i种灯泡需求的花费    区域考虑!考虑某一片都用这个灯泡
    */
    struct node
    {
        int v, k, c, l;
        bool operator<(const node& rhs)
        {
            return v < rhs.v;
        }
    }a[MAXN];
    int dp[MAXN], pre[MAXN], n;
    int main()
    {
        while (scanf("%d", &n), n)
        {
            memset(pre, 0, sizeof(pre));
            memset(dp, INF, sizeof(dp));
            for (int i = 1; i <= n; i++)
                scanf("%d%d%d%d", &a[i].v, &a[i].k, &a[i].c, &a[i].l);
            sort(a + 1, a + n + 1);
            int sum = 0;
            dp[0] = 0;
            for (int i = 1; i <= n; i++)
            {
                pre[i] = pre[i - 1] + a[i].l;
            }
            
            for (int i = 1; i <= n; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    dp[i] = min(dp[j] + (pre[i] - pre[j])*a[i].c + a[i].k,dp[i]);
                }
            }
            printf("%d
    ", dp[n]);
        }
    }

    G

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    #define MAXN  1009
    #define L 31
    #define INF 1000000009
    #define eps 0.00000001
    /*
    先用n2 时间维护一个二维数组记录i-j是不是回文字串
    然后dp
    */
    char str[MAXN];
    int dp[MAXN];
    bool vis[MAXN][MAXN];
    int main()
    {
        int n;
        scanf("%d", &n);
        while (n--)
        {
            memset(vis, false, sizeof(vis));
            scanf("%s", str + 1);
            int l = strlen(str + 1);
            for (int i = 1; i <= l; i++)
                vis[i][i] = true;
            for (int i = 1; i < l; i++)
            {
                if (str[i] == str[i + 1])
                    vis[i][i + 1] = true;
                else
                    vis[i][i + 1] = false;
            }
            for (int k = 2; k <= l; k++)
            {
                for (int i = 1; i <= l; i++)
                {
                    int j = i + k;
                    if (j > l) break;
                    if (str[i] == str[j] && vis[i + 1][j - 1])
                        vis[i][j] = true;
                }
            }
            memset(dp, INF, sizeof(dp));
            dp[0] = 0;
            for (int i = 1; i <= l; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if (vis[j+1][i])
                        dp[i] = min(dp[i], dp[j] + 1);
                }
            }
            printf("%d
    ", dp[l]);
        }
    }

    H

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #define INF 10e7
    using namespace std;
    int T,len1,len2;
    int dp[5005][5005];
    int st1[27],st2[27],ed1[27],ed2[27];
    char s1[5005],s2[5005];
    
    void dp_solve()
    {
        //int cnt=0,res=INF;
        for(int i=0; i<=len1; i++)
            for(int j=0; j<=len2; j++)
            {
                int cnt=0,res=INF;
                for(int k=0; k<26; k++)
                    if((i>=st1[k]||j>=st2[k])&&(i<ed1[k]||j<ed2[k]))//此处判断有多少种颜色已经出现但尚未结束
                        cnt++;
                if(i>0) res=min(res,dp[i-1][j]);
                if(j>0) res=min(res,dp[i][j-1]);
                dp[i][j]=cnt+(res==INF ? 0:res);
            }
        cout<<dp[len1][len2]<<endl;
    }
    
    int main()
    {
        cin>>T;
        while(T--)
        {
            scanf("%s%s",s1+1,s2+1);
            len1=strlen(s1+1);
            len2=strlen(s2+1);
            for(int i=0; i<26; i++)
            {
                st1[i]=st2[i]=INF;
                ed1[i]=ed2[i]=0;
            }
            int tmp;
            for(int i=1; i<=len1; i++)
            {
                tmp=s1[i]-'A';
                if(st1[tmp]==INF)  st1[tmp]=i;
                ed1[tmp]=i;
            }
            for(int i=1; i<=len2; i++)
            {
                tmp=s2[i]-'A';
                if(st2[tmp]==INF)  st2[tmp]=i;
                ed2[tmp]=i;
            }
            dp_solve();
        }
        return 0;
    }

    I

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #define INF 10e7
    using namespace std;
    int T,len1,len2;
    int dp[5005][5005];
    int st1[27],st2[27],ed1[27],ed2[27];
    char s1[5005],s2[5005];
    
    void dp_solve()
    {
        //int cnt=0,res=INF;
        for(int i=0; i<=len1; i++)
            for(int j=0; j<=len2; j++)
            {
                int cnt=0,res=INF;
                for(int k=0; k<26; k++)
                    if((i>=st1[k]||j>=st2[k])&&(i<ed1[k]||j<ed2[k]))//此处判断有多少种颜色已经出现但尚未结束
                        cnt++;
                if(i>0) res=min(res,dp[i-1][j]);
                if(j>0) res=min(res,dp[i][j-1]);
                dp[i][j]=cnt+(res==INF ? 0:res);
            }
        cout<<dp[len1][len2]<<endl;
    }
    
    int main()
    {
        cin>>T;
        while(T--)
        {
            scanf("%s%s",s1+1,s2+1);
            len1=strlen(s1+1);
            len2=strlen(s2+1);
            for(int i=0; i<26; i++)
            {
                st1[i]=st2[i]=INF;
                ed1[i]=ed2[i]=0;
            }
            int tmp;
            for(int i=1; i<=len1; i++)
            {
                tmp=s1[i]-'A';
                if(st1[tmp]==INF)  st1[tmp]=i;
                ed1[tmp]=i;
            }
            for(int i=1; i<=len2; i++)
            {
                tmp=s2[i]-'A';
                if(st2[tmp]==INF)  st2[tmp]=i;
                ed2[tmp]=i;
            }
            dp_solve();
        }
        return 0;
    }

    I 树形DP

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    #define MAXN  55
    #define L 31
    #define INF 1000000009
    #define eps 0.00000001
    
    /*
    dp[i][j] 为切割小木棍i-j点的费用
    dp[i][j] = a[j]-a[i](切割第一刀的费用) + dp[i][k] + dp[k][j] 从中间的k点切
    O(n3)
    */
    int l, n, a[MAXN];
    int dp[MAXN][MAXN];
    int main()
    {
        while (scanf("%d", &l), l)
        {
            memset(dp, INF, sizeof(dp));
            memset(a, 0, sizeof(a));
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
                scanf("%d", &a[i]);
            for (int i = 0; i <= n + 1; i++)
                dp[i][i] = 0;
            for (int i = 0; i < n + 1; i++)
                dp[i][i + 1] = a[i + 1] - a[i];
            a[0] = 0, a[n + 1] = l;
            for (int k = 1; k <= n + 1; k++)
            {
                for (int i = 0; i + k <= n + 1; i++)
                {
                    int j = i + k;
                    for (int t = i + 1; t < j; t++)
                        dp[i][j] = min(dp[i][j], dp[i][t] + dp[t][j] + a[j] - a[i]);
                }
            }
            printf("The minimum cutting is %d.
    ", dp[0][n + 1]);
        }
    }
  • 相关阅读:
    Day 03
    Day 03 作业
    Day 02 作业
    Day 02
    Day 01
    Day 10 面向对象基础
    Spring学习-- Bean 的作用域
    一、基本知识
    cloud-init使用技巧
    如何在KVM中管理存储池
  • 原文地址:https://www.cnblogs.com/joeylee97/p/7353815.html
Copyright © 2020-2023  润新知