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

 

posted @ 2011-08-30 20:15  AC_Von  阅读(1010)  评论(0编辑  收藏  举报