紫书 动态规划例题

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]);
    }
}
原文地址:https://www.cnblogs.com/joeylee97/p/7353815.html