• 20180828 DP解题报告


    保林哥的话

    本套题目检验了四类DP,当然DP肯定不仅有这里的几种类型,由于时间有限,简单和稍偏的DP未列举,未考知识点请同学们一定下来练习掌握。注:BCD三题提供简易题目大意,且题目顺序不代表题目的难易梯度,做题顺序和时间请自行把握!!!

    T1 HihoCoder 1798 666

    Description

    如果一个数字字符串(只包含0-9,可以有前导0)中出现且只出现1次666,我们就称这个字符串是好的。

    例如166603660666是好的,666666123不是好的。

    请你计算长度为N的数字字符串中,有多少个是好的。由于总数可能很大,你只需要输出总数模1000000007的余数。

    Input

    一个整数N

    对于30%的数据,1 ≤ N ≤ 8

    对于100%的数据,1 ≤ N ≤ 1000

    Output

    一个整数代表答案。

    题解

    dp[i][j]表示长度为i,开头有j6且串中没有666的串的数量

    这道题也就是将一个问题分成许多子问题,再合并求答案

    一道比较简单但很好的数位DP

    时间复杂度 (Theta(n))

    代码

    #include <bits/stdc++.h>
    const int kMod(1000000007);
    int n;
    long long dp[1010][3], ans;
    int main(int argc, char **argv) {
      scanf("%d", &n);
      dp[0][0] = 1;
      for (register int i(1); i <= n; ++i) {
        dp[i][0] = (dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2]) * 9 % kMod;
        dp[i][1] = dp[i - 1][0];
        dp[i][2] = dp[i - 1][1];
      }
      for (register int i(1); i < n - 1; ++i) {
        ans  = (ans + dp[i][1] * dp[n - i][2]) % kMod;
      }
      printf("%lld
    ", ans);
      return 0;
    }
    

    T2 Hrbust 2160 Hunter

    还没做出来,有时间再补

    T3 HDU 2196 Computer

    题目大意

    给出一棵树,求出以每个结点为开始的最长路

    题解

    非常经典的树形DP

    首先用邻接表存图(内存限制有点小而且有多组数据不敢用vector)

    默认以1为根结点,找到以每个结点在以自身为根的子树可以走过最长路径的长度(DFS)

    再找每个结点向根走的最长路(DFS)

    时间复杂度 (Theta(n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct Edge {
      int v, w, next;
    } edge[20010];
    int cnt, head[10010];
    inline void AddEdge(const int &u, const int &v, const int &w) {
      edge[cnt].v = v, edge[cnt].w = w;
      edge[cnt].next = head[u], head[u] = cnt++;
    }
    long long dp[3][10010];
    int destination[10010];
    inline void FirstDfs(const int &u, const int &father) {
      register long long maximum(0), second_maximum(0);
      for (register int i(head[u]); i != -1; i = edge[i].next){
        register int v(edge[i].v);
        if (v == father) continue;
        FirstDfs(v, u);
        if (maximum <= dp[0][v] + edge[i].w) {
          second_maximum = maximum, 
          maximum = dp[0][v] + edge[i].w, 
          destination[u] = v;
        }
        else if(second_maximum < dp[0][v] + edge[i].w) {
          second_maximum = dp[0][v] + edge[i].w;
        }
        else if(second_maximum < dp[1][v] + edge[i].w) {
          second_maximum = dp[1][v] + edge[i].w;
        }
      }
      dp[0][u] = maximum, dp[1][u] = second_maximum;
    }
    inline void SecondDfs(const int &u,const int &father) {
      for (register int i(head[u]); i != -1; i = edge[i].next) {
        register int v(edge[i].v);
        if (v == father) continue;
        if(destination[u] == v) {
          dp[2][v] = max(dp[1][u] + edge[i].w, dp[2][u] + edge[i].w);
        }
        else dp[2][v] = max(dp[0][u] + edge[i].w, dp[2][u] + edge[i].w);
        SecondDfs(v, u);
      }
    }
    int n, a, b;
    int main(int argc, char **argv) {
      while (~scanf("%d", &n)) {
        cnt = 0;
        memset(head, -1, sizeof(head));
        memset(dp, 0, sizeof(dp));
        for (register int i(2); i <= n; ++i) {
          scanf("%d %d", &a, &b);
          AddEdge(i, a, b), AddEdge(a, i, b);
        }
        FirstDfs(1, 1);
        SecondDfs(1, 1);
        for (register int i(1); i <= n; ++i) {
          printf("%lld
    ", max(dp[0][i], dp[2][i]));
        }
      }
      return 0;
    }
    

    T4 POJ 3071 Football

    题目大意

    ({2}^{n})个足球队,定义p[i,j]i队打败j队的概率,所有p[i,i]0,且1-p[i,j]=p[j,i]

    求夺冠几率最高的球队的编号

    题解

    概率DP,难度不大

    dp[i][j]i队赢j场比赛的概率,然后就简单了

    记得要先枚举比赛

    时间复杂度 (Theta(n cdot {2}^{2n}))

    代码

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    int n, m;
    double p[256][256];
    int winner;
    double winner_probability, dp[256][16];
    int main(int argc, char **argv) {
      while (std::cin >> n) {
        if (n == -1) return 0;
        m = 1 << n;
        memset(dp, 0, sizeof(dp));
        for (register int i(1); i <= m; ++i) {
          dp[i][0] = 1.0;
          for (register int j(1); j <= m; ++j) {
            scanf("%lf", &p[i][j]);
          }
        }
        for (register int j(1); j <= n; ++j) {
          for (register int i(1); i <= m; ++i) {
            for (register int k(1); k <= m; ++k) {
              if ((((i - 1) >> (j - 1)) ^ 1) == ((k - 1) >> (j - 1))) {
                dp[i][j] += dp[i][j - 1] * dp[k][j - 1] * p[i][k];
              }
            }
          }
        }
        winner_probability = -1, winner = 0;
        for (register int i(1); i <= m; ++i){
          if (dp[i][n] > winner_probability) {
            winner_probability = dp[i][n];
            winner = i;
          }
        }
        printf("%d
    ", winner);
      }
      return 0;
    }
    
  • 相关阅读:
    DataInputStream与DataOutputStream类
    BluetoothChat例程分析
    Android中的Handler机制
    我的IT之路2012(二)
    菜鸟学Java(二)——Filter解决中文乱码问题
    菜鸟学Java(一)——Ajax异步检查用户名是否存在
    FTP文件操作之创建目录
    FTP文件操作之获取文件列表
    使用powershell计算性能计数器的均值
    收缩临时库 shrink tempdb
  • 原文地址:https://www.cnblogs.com/forth/p/9548279.html
Copyright © 2020-2023  润新知