• poj DP专辑


    //打星号的表示个人认为比较经典,或是算法比较好的题目

    共80题,各种类型,背包,树形dp,状态dp。。。。

     

    1014* Dividing 半个背包,注意中断   √

    1036 Gangsters 

    f[i]表示第i个人成功进入后,前i个人的最优值。。。 f[i]由f[j]转移来,(0 <= j < i)。。。。注意T和S的值符合逻辑,一个250的错误,搞掉好几次wa。。。

     

    1038* Bugs Integrated, Inc. 状态压缩 √ http://www.cnblogs.com/vongang/archive/2012/07/30/2615322.html

     

    1050 To the Max 最大子矩形

    予处理一下矩阵,mat[i][j]表示第i行1...j列所有值的和。O(n^2)的时间枚举列区间,O(n)的时间找最大连续子序列,总共O(n^3)

     

    1080 Human Gene Functions

    简单dp,f[i][j]表示s1串到i位置,s2串到j位置的时的最优。

    初始化:f[0][0] = 0, f[i][0] = f[i-1][0] + mp[s1[i]]['-'], f[0][j] = f[0][j-1] + mp[s2[j]]['-'];  其它的赋值为-inf

     

    1088 滑雪

    傻冒级的记忆化搜索。。。我还写错了。。。

     

    1141* Brackets Sequence 括号序列

    递归输出的过程确实挺有意思,这次再做又忘了怎么写了。。。

    黑书上的原题。状态转移很容易写,主要是输出序列。用pos[i][j]记录f[i][j] = min(f[i][k]+ f[k+1][j], f[i][j]) 的k位置,初始化pos为-1,如果出现-1,则说明f[i][j]直接由f[i+1][j-1]转移而来,直接输出s[i] s[j],就可以。

     

    1157 LITTLE SHOP OF FLOWERS

    这个题应该挺简单吧,注意初始化就可以。别的真没什么可说的

     

    1159* Palindrome

    回文串,经典dp,n - 正序和逆序的最长公共子序列

     

     

     

    1170 Shopping Offers

    还算不错的背包,就是有点恶心。。。http://www.cnblogs.com/vongang/archive/2012/08/06/2624864.html

     

     

    1191 棋盘分割

    很经典的记忆化搜索,黑书上的例题,感觉记忆化搜索好神,哈。

     

    tmp = inf;
    
    for(i = x1; i < x2; ++i) {
            tmp = min(tmp, dfs(x1, y1, i, y2, k - 1) + area(i + 1, y1, x2, y2));
            tmp = min(tmp, dfs(i + 1, y1, x2, y2, k - 1) + area(x1, y1, i, y2));
        }
    for(i = y1; i < y2; ++i) {
            tmp = min(tmp, dfs(x1, y1, x2, i, k - 1) + area(x1, i + 1, x2, y2));
            tmp = min(tmp, dfs(x1, i + 1, x2, y2, k - 1) + area(x1, y1, x2, i));
    }
    
    f[x1][y1][x2][y2][k] = tmp;

     

     

    1276 Cash Machine

     裸多重背包

     

    1322 Chocolate

     一道概率为题面的题。。。纠结了半天以为是数论推规律,没想到是很裸的dp。f[i][j]表示包里有i个物体,桌子上留下j个球的概率 f[i][j] = f[i-1][j-1]*(c - i + 1)/c, f[i-1][j+1]*(i + 1)/c;

    为什么是c呢?因为如果m>c的话。。。那种情况不可能出现,还有就是m和n的奇偶性相同。否则概率为0;

     

     

    1458 Common Subsequence

     最长公共子序列,应该算是道水题。。。不过这题居然没给数据量,本菜难得的贡献一次MLE,我哭!。。。

     

    1661 Help Jimmy

     注意一个trick,小人从上往下掉的时候,比如区间[-50, 100], [0, 100]它可以从上一个100跳到下一个100

    详见 http://www.cnblogs.com/vongang/archive/2012/08/07/2626234.html

     

    1745 Divisibility

     题意:给n个数,对这n个数中间加上+或则-,求和判断这个和能否整除k。想到用背包求这些和所能达到的值。。。因为数据量的问题会MLE。。然后看了一下解题报告,发现犯了一个很二的错误,整除k这个条件,可以每个值都模k。。。这都没想到!T_T

    ps:因为有负数,所以要加一个偏移量,因为k最多为100,所以个偏移量定义为100就行。

     

    View Code
    const int N = 220;
    const int zero = 100;
    
    bool f[2][N];
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, num, k, i, j, t;
        while(~scanf("%d%d", &n, &k)) {
            CL(f, false);
            t = 0; f[0][zero] = true;
            for(i = 1; i <= n; ++i) {
                scanf("%d", &num);
                num %= k;
                for(j = zero + k; j >= zero - k; --j) {
                    if(f[t][j]) {
                        f[t^1][(j- zero + num)%k + zero] = true;
                        f[t^1][(j- zero - num)%k + zero] = true;
                    }
                }
                for(j = zero + k; j >= zero - k; --j) {
                    f[t][j] = f[t^1][j];
                    f[t^1][j] = false;
                }
            }
            if(f[t][zero])  puts("Divisible");
            else    puts("Not divisible");
        }
        return 0;
    }

     

     

    1837 Balance

    同上,加一个偏移量

     

     

    1770 Special Experiment

     

    1828 Monkeys' Pride

    个人感觉题目有问题。。。。

     

    1836 Alignment

    好题,大坑题啊=,=   题目是要找中间一个(或几个)最高,然后向左向右都是降序的最长序列。可以分别求从左到右的f1[i]和从右往左的f2[i]最长上升子序列, f1[i] + f2[i]就是当前点的最长序列,不过别忘了或几个最高 这是一个大坑,从左右开始枚举,如果出现相同的高度,这两个序列是可以和到一块的。
     

    View Code
    const int N = 1024;
    
    double a[N];
    int f1[N], f2[N];
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, i, j;
        while(~scanf("%d", &n)) {
            REP(i, n)   {scanf("%lf", a + i); f1[i] = f2[i] = 1;}
    
            REP(i, n) {
                REP(j, i) {
                    if(a[i] - a[j] > eps)    f1[i] = max(f1[i], f1[j] + 1);
                }
            }
            for(i = n - 1; i >= 0; --i) {
                for(j = n - 1; j > i; --j) {
                    if(a[i] - a[j] > eps)    f2[i] = max(f2[i], f2[j] + 1);
                }
            }
    
            int ans = 0;
    
            REP(i, n) {
                for(j = n - 1; j >= i; --j) {
                    if(i == j)  {ans = max(ans, f1[i] + f2[i] - 1); continue;}
                    if(a[i] == a[j])    ans = max(ans, f1[i] + f2[j]);
                }
            }
            printf("%d\n", n - ans);
        }
        return 0;
    }

     

     

     

    1848* Tree

    确实挺好的题,状态转移太神奇了。。。Orz

    详见:http://www.cnblogs.com/vongang/archive/2012/08/12/2634763.html

     

     

    1862 Stripies

    不明白为什么归类到dp里边。。。这明明就是贪心,数学性质很容易看出来。按从大到小排序,然后递推公式。。。难道因为这个递推公式?太淫荡了吧。!

     

     

    1925* Spiderman

     败给这题了。。。以前做过,记得是按坐标dp的,一看数据没敢写,后来翻了一下以前的解题报告。。。发现一个很有利的剪枝才感谢。。。然后没有注意a*a + b*b > c*c这个式子可能超int。。。贡献N次wa。。。T_T。

     

    1946* Cow Cycling

    设 f[ld][sp][e][dis] 表示当前leader是ld,以速度sp到达能量剩余为e,行走距离为dis的状态所用的最少时间。

    然后记忆化搜索可破。详见:http://www.cnblogs.com/vongang/archive/2012/08/13/2636475.html

     

     

    1948 Triangular Pastures

    蛋疼,题目有个条件,所有的边都要用到。。。偶无语了,没有看到这个条件,这题做了一天。。。

    既然所有的边都要用到,那么只需要切定两个边,另外一条边就确定了。按背包的思想确定两条边,这里注意初始化一下,不能到达的状态为-1,f[0][0] = 0;

    因为三角形的性质,每条边都是<sum/2的。可以减小一些计算量。

     

    1952 BUY LOW, BUY LOWER

     最长下降子序列,不过还要记录最长为max的下降子序列有多少个。并且,相同的序列只能算作一个。。。就是这个地方wa了n次。。。

     

    View Code
     1         REP(i, n) {
     2             for(j = i - 1; j >= 0; --j) {
     3                 if(num[i] < num[j]) {
     4                     if(f[j] + 1 > f[i]) {f[i] = f[j] + 1; a[i] = a[j];}
     5                     else if(f[j] + 1 == f[i]) {a[i] += a[j];}
     6                     mx = max(mx, f[i]);
     7                 } else if(num[i] == num[j]) {
     8                     if(f[i] == 1)   a[i] = 0;
     9                     break;
    10                 }
    11             }
    12         }

     

     

     

     

    1985 Cow Marathon 

    没有写dp,两个bfs过的。先任意找一点bfs,找到离这个点最远的点t,然后从t开始bfs,找最大距离。这题让我想起来tc上的一道题。。。Orz出题人。

     

     

     

    2057* The Lost House 

     好题,详见:http://www.cnblogs.com/vongang/archive/2012/08/20/2647703.html

     

    2137 Cowties 

     写了一个很搓的状态,没想到居然能过。。。f[i][j][s]表示从第0头牛喜欢的s点出发,到达第i都牛喜欢的j点的最短路径。因为最后一头牛的点要跟 s相连才能构成环

    f[i][j][s] = min(f[i][j][s], f[i-1][k][s] + dis(g[i-1][k], g[i][j]);

    注意0-1, (n-1)->0这些边界点。复杂度O(n*m*m*m)....

     

    2181 Jumping Cows 

     吃饱撑的写贪心,还把思路想错了。。。我就是蛋疼!

    odd[i]表示到第i位置,最后一个选的值为奇数次选的最大值 (也就是+num[k], k < i)

    even[i]表示到第i位置,最后一个选的值为偶数次选的最大值 (同理 - num[k], k < i)

     odd[i] = max(odd[i-1], even[i-1] + num[i]);

     even[i] = max(even[i-1], odd[i-1] + num[i]);

     

      

     

    2184 Cow Exhibition

     

    2192 Zipper 

     看到discuss里好多人用记忆化搜索。表示写了一个O(n*len*len)的方程 63ms过来,估计后台不怎么强。。。。string3数组开小了。。。wa了一次T_T

    f[i][j]表示string1到i位置,string2到j位置组成的串跟string3的最大匹配长度。

     

    if(a[i] == c[i+j]) f[i][j] = max(f[i][j], f[i-1][j] + 1);
    if(b[j] == c[i+j]) f[i][j] = max(f[i][j], f[i][j-1] + 1);

    注意初始化,(让串从下标1开始更好处理,^_^)

      

    2231 Moo Volume 

    排序一下水过了,数据类型是long long 。。。T_T

     

    **2241 The Tower of Babylon

     自己打上星号吧,个人感觉还不错的题。开始的时候被坑了。。。额,不对,是我自己想错了。因为以前做过黑书上一个类似的题,也是积木游戏,所以这个题也当那种题做了,后来发现根本不对,这个是有优先顺序的。

     一个很巧妙的方法是把它转化成图。A面上可以放B面的话,A->B 权值为B的高度。然后找一条最长路,加上底座的高度就是结果。

    ps:Floyd偶都写错了,这题卡了两天。。。

     

    2250 Compromise 

     最长公共子序列。

    2264 Advanced Fruits

    2287* Tian Ji -- The Horse Racing 

     好吧,这是好题。。。偶忘了一点。就是如果田忌的马打不过齐王的马,那就用最次的马跟齐王比。。。。

    排序,f[i][j]表示齐王用到前i匹马,田忌用到前j匹马得到的最优值.

    f[i][j] = max {

    f[i-1][j-1] + cmpare(i, j);  

    f[i-1][j] + cmpare(i, n-i+1 + j);  //打不过就用最次的顶上。

    }  (j < i)

     初始化的注意一下 f[i][i] = f[i-1][i-1] + cmpare(i, i);  f[i][0] = f[i-1][0] + cmp(i, n - i + 1); //跟齐王的i号马,田忌的0号马

     

     

    2353 Ministry 

     题目好土,见过这种类型的题。。。dp[i][j]表示到达i,j位置的最小消耗,开一个结构体pre[i][j]存放[i][j]的前驱坐标...对每一行,从左望右扫一遍,从右望左扫一遍。。。。

      

     

    2385 Apple Catching 

    dp[i][1][w]表示到第i秒,在1号树下往返w次的最优值,dp[i][2][w]是在2号树下。

    为了安全其间,没仔细想,把所有的状态都写上了。

     

    if(num[i] == 1) {
        dp[i][1][j] = max(dp[i][1][j], dp[i-1][1][j] + 1);
        if(j > 0)   dp[i][1][j] = max(dp[i][1][j], dp[i-1][2][j-1] + 1);
    
        dp[i][2][j] = max(dp[i][2][j], dp[i-1][2][j]);
        if(j > 0)   dp[i][2][j] = max(dp[i][2][j], dp[i-1][1][j-1]);
    } else {
        dp[i][2][j] = max(dp[i][2][j], dp[i-1][2][j] + 1);
        if(j > 0)   dp[i][2][j] = max(dp[i][2][j], dp[i-1][1][j-1] + 1);
    
        dp[i][1][j] = max(dp[i][1][j], dp[i-1][1][j]);
        if(j > 0)   dp[i][1][j] = max(dp[i][1][j], dp[i-1][2][j-1]);
    }

     

     

    2392 Space Elevator 

    按a排序,然后多重背包。。。我二了。。。

     

    *2404 Jogging Trails

    还不错的题吧,虽然dp解法有点耍流氓。。。

    经典的中国邮递员问题。解法是对于度为奇数的点(一定为偶数个),构造一个完全图。然后找这个完全图的最小完美匹配(因为点数一定为偶数,所以完美匹配异一定存在)。。。可以用KM算法解二分图带权匹配中的最小匹配。不过这里数据规模太小了。直接用状态dp就可以。f[status]表示当前状态的最小完美匹配。转移的时间枚举任意两点,如果状态合法就可以转移。

    f[]初始化为inf,f[0] = 0;

     

     

    2411 Mondriaan's Dream

     状态压缩,还是用记忆化搜索写起来方便。。。递推式搞了半天也没写出来。。。初始化不会写。。。T_T

     

    2475* Any fool can do it 

    看着是编译原理里面的词法分析。。。其实,不是LR(0), 不是LR(1),也不是SLR(0)...

    记忆化搜索就可以。当前区间为[i, j],考虑几种情况:

    1、str[i] == '}' 或者 str[i] == ',' 这时,后面必需跟一个 ',' 而且 [i + 2, j]这个区间不能为空

    2、str[i] == '{' 时,后面可以跟一个','并且[i+2, j]不为空;也可以找到一个k,str[k] = '}' ( i + 1 <= k < j) 此时[i,j]构成一个子set集合,并且str[k+1] = ','后面跟一个List([k+2, j]不能为空)

    ps:本菜很二很二的。。。把记忆话搜索写成爆搜。。。贡献数次wa = =

     

    View Code
    //#pragma comment(linker,"/STACK:1024000000,1024000000")
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <functional>
    #include <numeric>
    #include <sstream>
    #include <stack>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    #define iabs(x) (x) < 0 ? -(x) : (x)
    #define OUT(x)  printf("%I64d\n", x)
    #define lowbit(x)   (x)&(-x)
    #define Read()    freopen("data.in", "r", stdin)
    #define Write()   freopen("data.out", "w", stdout);
    
    const double eps = 1e-8;
    typedef long long LL;
    const int inf = ~0u>>2;
    
    using namespace std;
    
    const int N = 220;
    int dp[N][N];
    char str[N];
    vector<int> g[N];
    
    bool dfs(int i, int j) {
        if(dp[i][j] != -1)  return dp[i][j];
        if(i >= j)  {dp[i][j] = 1; return true;}
        if(str[i] == '{') {
            if(str[j] == '}' && dfs(i + 1, j - 1))  {dp[i][j] = 1; return true;}
    
            for(int l = 0; l < int(g[i].size()); ++l) {
                int k = g[i][l];
                if(k + 1 >= j)  break;
                if(str[k] == '}' && str[k+1] == ',' && k + 1 < j) {
                    if(dfs(i + 1, k - 1) && dfs(k + 2, j)) {dp[i][j] = 1; return true;}
                    //break;
                }
            }
            if(i + 1 < j && str[i+1] == ',' && dfs(i + 2, j))   {dp[i][j] = 1; return true;}
            {dp[i][j] = false; return false;}
        }
        if(str[i] == '}' || str[i] == ',') {
            if(i + 1 < j && str[i+1] == ',' && dfs(i + 2, j))   {dp[i][j] = 1; return true;}
            {dp[i][j] = false; return false;}
        }
    }
    
    int main() {
        //Read();
    
        int n, len, i, j, cas = 0;
        scanf("%d", &n);
        while(n--) {
            scanf("%s", str);
            len = strlen(str);
            CL(dp, -1);
            for(i = 0; i < len; ++i) {    //把 str[i] = '{', str[k] = '}'的情况预处理出来。
                if(str[i] != '{')   continue;
                g[i].clear();
                for(j = i + 1; j < len; ++j) {
                    if(str[j] == '}')   g[i].push_back(j);
                }
            }
            if(str[0] == '{' && str[len-1] == '}' && dfs(1, len - 2))   printf("Word #%d: Set\n", ++cas);
            else    printf("Word #%d: No Set\n", ++cas);
        }
        return 0;
    }

     

     

    2479 Maximum sum 

    算是水题吧。d1[i]表示前i个数的最大子段和,d2[i]表示i到n区间的最大子段和。ans = max{d1[i] + d2[i+1]};

     

     

    2486* Apple Tree

    2559* Largest Rectangle in a Histogram

    2593 Max Sequence

    2663 Tri Tiling

    2677* Tour 双调欧几里德TSP

    经典问题,详见:http://www.cnblogs.com/vongang/archive/2012/09/15/2686576.html

    2726 Holiday Hotel

    2817* WordStack

    2923 Relocation

    2938* Economic Phone Calls

    2948 Martian Mining

    3036 Honeycomb Walk

    3042 Grazing on the Run

    3046 Ant Counting

    3088 Push Botton Lock

    3132 Sum of Different Primes

    3133* Manhattan Wiring 插头dp

    3140 Contestants Division

    3171 Cleaning Shifts

    3184 Finicky Grazers

    3186 Treats for the Cows

    3211 Washing Clothes

    3230 Travel

    3254 Corn Fields

    3257 Cow Roller Coaster

    3265 Problem Solving

    3267 The Cow Lexicon

    3272 Cow Traffic

    3298 Antimonotonicity

    3342 Party at Hali-Bula

    3345 Bribing FIPA

    3356 AGTC

    3459 Projects

    3519 Minimal Backgammon

    3616 Milking Time

    3638 Moogle

    3666 Making the Grade

  • 相关阅读:
    jquery接收后台数组或集合回显复选框
    解决微信小程序滑动遮罩时底层跟着滑动的问题
    前端实现滑动开关
    css简单动画
    MyBatis的数据库操作
    前端开发面试题-JavaScript(转载)
    前端开发面试题-CSS(转载)
    前端开发面试题-HTML(转载)
    H5 canvas 实现飞机大战游戏
    vuejs学习笔记(1)--属性,事件绑定,ajax
  • 原文地址:https://www.cnblogs.com/vongang/p/2159967.html
Copyright © 2020-2023  润新知