黑书上的DP例题

pagesectionnotitlesubmit
1131.5.1例题1括号序列POJ1141
1161.5.1例题2棋盘分割POJ1191
1171.5.1例题3决斗Sicily1822
1171.5.1例题4“舞蹈家”怀特先生ACM-ICPC Live Archive
1191.5.1例题5积木游戏http://202.120.80.191/problem.php?problemid=1244
1231.5.2例题1方块消除http://poj.org/problem?id=1390
1231.5.2例题2公路巡逻http://202.120.80.191/problem.php?problemid=1600
1251.5.2例题3并行期望值POJ1074
1311.5.2例题6不可分解的编码http://acmicpc-live-archive.uva.es/nuevoportal/data/problem.php?p=2475
1331.5.2例题7青蛙的烦恼http://codewaysky.sinaapp.com/problem.php?id=1014
1351.5.2例题9最优排序二叉树http://judge.noi.cn/problem?id=1059
1381.5.2例题10Bugs公司POJ1038
1391.5.2例题11迷宫统计http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=70&page=show_problem&problem=1472
1421.5.2例题12贪吃的九头龙http://judge.noi.cn/problem?id=1043
1511.5.3问题2最长上升子序列问题http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=17&page=show_problem&problem=1475
1511.5.3问题3最优二分检索树http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=15&page=show_problem&problem=1245
1521.5.3问题4任务调度问题POJ1180
1211.5.11.5.8艺术馆的火灾http://221.192.240.23:9088/showproblem?problem_id=1366
1441.5.21.5.10快乐的蜜月http://judge.noi.cn/problem?id=1052
1451.5.21.5.12佳佳的筷子http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=14&page=show_problem&problem=1212
1461.5.21.5.13偷懒的工人POJ1337
1461.5.21.5.15平板涂色POJ1691
1471.5.21.5.16道路重建POJ1947
1471.5.21.5.17圆和多边形http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1679
1481.5.21.5.18Jimmy落地POJ1661
1481.5.21.5.19免费糖果http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=13&page=show_problem&problem=1059
1571.5.31.5.22回文词POJ1159
1571.5.31.5.24邮局POJ1160
1581.5.31.5.26奶牛转圈POJ1946
1581.5.31.5.27元件折叠http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=14&page=show_problem&problem=1180

现在开始训练一下DP:

递归动机的DP:

pku 1141 Brackets Sequence

黑书上讲的第一个题目,题意就给出一个括号序列,包含有"(" ")" "[" "]" 求最少添加的括号数是的最终的序列是合法的并输出这个序列。

思路:
首先这里求解的话要使用递归的思路,这是动态规划产生的第一种动机,于是我们可以写出记忆化搜索。进行求解。

dp[l][r] = min(dp[l][r],dp[l + 1][r - 1])如果s[l]与s[r]匹配的话。

否则我们就将该序列分成两段分别求解(这也是求解DP线性模型的一种递归分解思路)

dp[l][r] = min(dp[l][r],dp[l][k] + dp[k + 1][r])

这里关键是怎么讲可行解输出呢?开始我是通过比较dp[l][r] 与 dp[l + 1][r  -1] dp[l][k] + dp[k + 1][r]来判断的后来发现这样不对的 如果dp[l + 1][r - 1] = dp[l][k] + dp[k + 1][r]的话就会出现错误,而我们这里dp[l][r]确实从dp[l][k] + dp[k + 1][r]来的。所以,我们要另开一个二维数组记录每种最优状态的来源点。然后再递归的输出即可。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 115

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int dp[N][N];
char s[N];
int mk[N][N];

bool cmp(char a,char b)
{
    if ((a == '(' && b == ')') || (a == '[' && b == ']')) return true;
    return false;
}
int dfs_DP(int l,int r)
{
    int k;
    if (l > r) return 0;
    if (l == r) return (dp[l][r] = 1);
    if (dp[l][r] != inf) return dp[l][r];

    if (cmp(s[l],s[r]))
    {
        if (l + 1 == r)
        {
            dp[l][r] = 0;
            mk[l][r] = -1;
        }
        else
        {
            dfs_DP(l + 1,r - 1);
            if (dp[l][r] > dp[l + 1][r - 1])
            {
                dp[l][r] = dp[l + 1][r - 1];
                mk[l][r] = -1;
            }

    //        dp[l][r] = min(dp[l][r],dfs_DP(l + 1,r - 1));
//             printf(">>>**%d %d %d %d\n",l,r,dp[l][r],dp[l + 1][r - 1]);
        }
    }

    for (k = l; k <= r - 1; ++k)
    {
        dfs_DP(l,k); dfs_DP(k + 1,r);
        if (dp[l][r] >  dp[l][k] + dp[k + 1][r])
        {
            dp[l][r] = dp[l][k] + dp[k + 1][r];
            mk[l][r] = k;
        }
//        dp[l][r] = min(dp[l][r],dfs_DP(l,k) + dfs_DP(k + 1,r));
    }
    return dp[l][r];
}


void print(int l,int r)
{
    if (l > r) return;
    if (l == r)
    {
        if (s[l] == '(' || s[l] == ')') printf("()");
        else if (s[l] == '[' || s[l] == ']') printf("[]");
        return;
    }
    if (cmp(s[l],s[r]) && mk[l][r] == -1)
    {
        printf("%c",s[l]);
        print(l + 1,r - 1);
        printf("%c",s[r]);
    }
    else
    {
        print(l,mk[l][r]);
        print(mk[l][r] + 1,r);
    }
}
int main()
{
//   Read();
//   Write();
   int i,j;
   scanf("%s",s);
   int n = strlen(s);
   CL(mk,-1);
   for (i = 0; i <= n; ++i)
   {
       for (j = 0; j <= n; ++j)
       {
           dp[i][j] = inf;
       }
   }
   dfs_DP(0,n - 1);
//   printf("%d\n",dp[0][n - 1]);
   print(0,n - 1);
   printf("\n");
   return 0;
}

 

 pku 1191 棋盘分割

思路:
棋盘横着切竖着切,然后递归将棋盘不断缩小到能够求解的状态。记忆化搜索。这里中间计算值可能会超0x7f7f7f7f,所以最大值取大一点。这里让哥条了很长时间。。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 10

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int mat[N][N];
int s[N][N][N][N];
int dp[N][N][N][N][20];
ll map[N][N];

int n;

int DP(int x1,int y1,int x2,int y2,int no)
{
    int x,y;
    if (no == 1) return dp[x1][y1][x2][y2][no];
    if (dp[x1][y1][x2][y2][no] != -1) return dp[x1][y1][x2][y2][no];
    int ans = 999999999;
    for (x = x1; x < x2; ++x)
    {
        ans = min(ans,min(DP(x1,y1,x,y2,no - 1) + s[x + 1][y1][x2][y2],DP(x + 1,y1,x2,y2,no - 1) + s[x1][y1][x][y2]));
    }
    for (y = y1; y < y2; ++y)
    {
          ans = min(ans,min(DP(x1,y1,x2,y,no - 1) + s[x1][y + 1][x2][y2],DP(x1,y + 1,x2,y2,no - 1) + s[x1][y1][x2][y]));
    }
    return (dp[x1][y1][x2][y2][no] = ans);
}
int main()
{
//    Read();
    int i,j;
    scanf("%d",&n);
    int sum = 0;
    for (i = 1; i <= 8; ++i)
    {
        for (j = 1; j <= 8; ++j)
        {
            scanf("%d",&mat[i][j]);
            sum += mat[i][j];
        }
    }

    CL(s,0); CL(dp,-1);
    int x1,y1,x2,y2;
    for (x1 = 1; x1 <= 8; ++x1)
    {
        for (y1 = 1; y1 <= 8; ++y1)
        {
            for (x2 = x1; x2 <= 8; ++x2)
            {
                for (y2 = y1; y2 <= 8; ++y2)
                {
//                    printf("%d %d %d %d\n",x1,y1,x2,y2);
                    for (i = x1; i <= x2; ++i)
                    {
                        for (j = y1; j <= y2; ++j)
                        {
                            s[x1][y1][x2][y2] += mat[i][j];
                        }
                    }

                    s[x1][y1][x2][y2] *=  s[x1][y1][x2][y2];

                    dp[x1][y1][x2][y2][1] = s[x1][y1][x2][y2];
                }
            }
        }
    }


    DP(1,1,8,8,n);
    double ans = (1.0*dp[1][1][8][8][n])/(1.0*n) - (1.0*sum*sum)/(1.0*n*n);
    printf("%.3f\n",sqrt(ans));
    return 0;
}

 

 sicily 1822 Fight Club

题意:黑书

思路:

开始吧题意理解错了,一位如果判断i必须从i开始一次与i + 1,i +2比较呢。SB了。。

dp[i][j]表示i能否与j相遇,记住这里是相遇不表示i与j谁能打败谁。如果判断x点,我们把x点查分为x与n + 1,这样讲原来的环转化成连,然后求x与n +1是否能够相遇即可

dp[i][j] = (dp[i][k] && dp[k][j] && (mat[i][k],mat[j][k])),mat[i][j]表示i能否打败j

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 50

using namespace std;

const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int mat[N][N];

int dp[N][N];
int seq[N];
bool vt[N][N];

int n;
int DP(int l,int r)
{
    int k;
    if (vt[l][r]) return dp[l][r];

    for (k = l + 1; k <= r - 1; ++k)
    {
        dp[l][r] = (DP(l,k)&&DP(k,r)&&(mat[seq[l]][seq[k]] || mat[seq[r]][seq[k]]));
        if (dp[l][r]) break;
    }
    vt[l][r] = true;
    return dp[l][r];
}
int main()
{
//    Read();
    int T,i,j;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        CL(mat,0);
        for (i = 1; i <= n; ++i)
        for (j = 1; j <= n; ++j)
        scanf("%d",&mat[i][j]);


        for (i = 1; i <= n; ++i)
        {
            CL(dp,0); CL(vt,false);

            int pos = (i - 1);
            if (pos == 0) pos = n;

            int ln = 0;
            for (j = i; j <= n; ++j) seq[++ln] = j;
            for (j = 1; j <= i - 1; ++j) seq[++ln] = j;
            seq[++ln] = n + 1;

            for (j = 1; j <= n; ++j)
            {
                dp[j][j + 1] = dp[j + 1][j] = 1;
                vt[j][j + 1] = vt[j + 1][j] = true;
            }

            DP(1,ln);
            if (dp[1][ln]) printf("1\n");
            else printf("0\n");
        }
//        if (T != 0)
        printf("\n");
    }

    return 0;
}

 

hdu 3632 A Captivating Match

题意:

这题和上题目意思一样,只不过这里是序列1-n然后每个人可以选择左右两边的人进行对决,我刚开始看到这题目的时候,就以为是上边那道题目,结果样例过了,就是不对。

思路:
这里某个人i如果能够胜出,那么他一定能够和0点并且和n + 1点相遇。(与上题一样,抽象出来的两个点)。然后我们只要枚举任意两点是否能够相遇即可,

dp[i][j] = (dp[i][k] && dp[k][j] && (mat[i][k],mat[j][k])),mat[i][j]表示i能否打败j,   这里根据i到j的距离进行递推的。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 30007
#define N 117

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;

int val[N];
int mat[N][N];
int n;
int dp[N][N];
bool vt[N][N];

bool isok(int i,int j,int k)
{
    if (dp[i][k] && dp[k][j] && (mat[i][k] || mat[j][k])) return true;
    else return false;
}
int main()
{
//    Read();
    int T,i,j;
    int cas = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (i = 1; i <= n; ++i) scanf("%d",&val[i]);
        CL(mat,0);//记住要初始化
        for (i = 1; i <= n; ++i)
        for (j = 1; j <= n; ++j) scanf("%d",&mat[i][j]);

        CL(dp,0);
        for (i = 0; i <= n + 1; ++i) dp[i][i + 1] = dp[i + 1][i] = 1;
        int k,p;
        for (k = 2; k <= n; ++k)//递推策略
        {
            for (i = 0; i + k <= n + 1; ++i)
            {
                j = i + k;
                for (p = i + 1; p <= j - 1; ++p)
                {
                    if (isok(i,j,p))
                    {
                        dp[i][j] = 1;
                    }
                }
            }
        }
        int ans = 0;
        for (i = 1; i <= n; ++i)
        {
            if (dp[0][i] && dp[i][n + 1] && val[i] > ans) ans = val[i]; //i能否杀到0并且能够杀到n + 1
        }
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}

 

pku 1390 Blocks

题意:看给书吧..

思路:

我们考虑的是最后一段是单独消去还是和前边的一起消去,这样就可以构造出递归的递推式了。

题目的方块可以表示称color[i],len[i],1<=i<=l
这里l表示有多少"段"不同的颜色方块
color[i]表示第i段的颜色,len[i]表示第i段的方块长度
让f[i,j,k]表示把(color[i],len[i]),(color[i+1],len[i+1]),...,(color[j-1],len[j-1]),(color[j],len[j]+k)合并的最大得分
考虑(color[j],len[j]+k)这一段,要不马上消掉,要不和前面的若干段一起消掉
1.如果马上消掉,就是f[i,j-1,0]+(len[j]+k)^2
2.如果和前面的若干段一起消,可以假设这"若干段"中最后一段是p,则此时的得分是f[i,p,k+len[j]]+f[p+1,j-1,0]
于是f[i,j,k] = max{ f[i,j-1,0]+(len[j]+k)^2, f[i,p,k+len[j]]+f[p+1,j-1,0] 

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include <utility>


#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 207

using namespace std;

const int inf = 0x7f7fffff;
const ll mod = 1000000007;

int dp[N][N][N];
int a[N],of[N],b[N];
int n,ln;

int q_DP(int l,int r,int k)
{
    int p;
    if (dp[l][r][k] != 0) return dp[l][r][k];
    if (l == r)
    {
        return (dp[l][r][k] = (b[r] + k)*(b[r] + k));
    }
    int ans = 0;
    ans = max(ans,q_DP(l,r - 1,0) + (b[r] + k)*(b[r] + k));

    for (p = l; p + 1 <= r - 1; ++p)
    {
        if (of[r] == of[p])
        ans = max(ans,q_DP(l,p,k + b[r]) + q_DP(p + 1,r - 1,0));
    }
    return dp[l][r][k] = ans;
}
int main()
{
//    Read();
    int i;

    int T,cas = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        ln = 0; CL(a,0);
        for (i = 0; i < n; ++i)
        {
            scanf("%d",&a[i]);
        }
        ln = 0; int ct = 0;
        for (i = 0; i < n; ++i)
        {
            if (a[i] != a[i + 1])
            {
                b[++ln] = ct + 1;
                of[ln] = a[i];
                ct = 0;
            }
            else ct++;
        }
//        b[++ln] = ct;
//        of[ln] = a[n - 1];
        CL(dp,0);
        q_DP(1,ln,0);
        printf("Case %d: %d\n",cas++,dp[1][ln][0]);
    }
    return 0;
}

 

 

 

 

 多决策动机的DP:

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=32

题意:黑书。。

思路:
这里每一步要么走左腿,要么走右腿,要么原地不动。DFS求解肯定超时,因为状态数太多,所以我们只好利用DP记录所有状态,然后通过每一步的决策。求解所有满足条件的状态。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 10017

using namespace std;

const int inf = 0x7f7fffff;
const int mod = 1000000007;

int a[N];
int dp[5][5][3];


int getS(int x,int y)
{
    if (x == 0) return 2;
    else if (x == y) return 1;
    else if (abs(x - y) == 2) return 4;
    else return 3;
}
int main()
{
//    Read();
    int i,j,k;
    int n;
    a[0] = 0;
    while (~scanf("%d",&a[1]))
    {
        if (a[1] == 0) break;
        i = 2;
        while (scanf("%d",&a[i]))
        {
            if (a[i] == 0) break;
            i++;
        }
        n = i - 1;

        for (i = 0; i <= 4; ++i)
        {
            for (j = 0; j <= 4; ++j)
            {
                for (k = 0; k <= 1; ++k)
                dp[i][j][k] = inf;
            }
        }

        dp[0][0][0] = 0;
        int u = 0, v = 1;
        for (k = 0; k < n; ++k)
        {
            for (i = 0; i <= 4; ++i)
            {
                for (j = 0; j <= 4; ++j)
                {
                    if (dp[i][j][u] != inf)
                    {
                        if (a[k + 1] != j) //保证左右脚不能在一起
                        dp[a[k + 1]][j][v] = min(dp[a[k + 1]][j][v],dp[i][j][u] + getS(i,a[k + 1]));
                        if (i != a[k + 1])
                        dp[i][a[k + 1]][v] = min(dp[i][a[k + 1]][v],dp[i][j][u] + getS(j,a[k + 1]));
                    }
                }
            }
            swap(u,v); //滚动数组优化
            for (i = 0; i <= 4; ++i)
            {
                for (j = 0; j <= 4; ++j)
                {
                    dp[i][j][v] = inf;
                }
            }

        }

        int ans = inf;
        for (i = 0; i <= 4; ++i)
        {
            if (i != a[n])
            ans = min(dp[i][a[n]][u],ans);
        }
        for (j = 0; j <= 4; ++j)
        {
            if (j != a[n])
            ans = min(dp[a[n]][j][u],ans);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

积木游戏

题意:。。。

思路:
就是按着黑书上的第一种思路做的,这里有个地方卡了一下, 就是j表示的类成了j堆,在枚举的时候不能只到m-1否则最后累到第m的堆的最后一个也就不存在了,。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include <utility>


#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 107

using namespace std;

const int inf = 0x7f7fffff;
const ll mod = 1000000007;

int dp[N][N][N][4];
bool vt[N][N][N][4];
int a[N][4][4];
int n,m;

bool over(int i,int x,int j,int y)
{
    int sda = max(a[i][x][0],a[i][x][1]);
    int sdb = min(a[i][x][0],a[i][x][1]);
    int pda = max(a[j][y][0],a[j][y][1]);
    int pdb = min(a[j][y][0],a[j][y][1]);
    if (sda <= pda && sdb <= pdb) return true;
    else return false;
}
int main()
{
//    Read();
    int i,j,k,p,q;
    int x,y,z;

    scanf("%d%d",&n,&m);
    CL(a,0);
    for (i = 1; i <= n; ++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        //表示第i个面的的长宽高
        a[i][0][0] = x; a[i][0][1] = y; a[i][0][2] = z;
        a[i][1][0] = y; a[i][1][1] = z; a[i][1][2] = x;
        a[i][2][0] = z; a[i][2][1] = x; a[i][2][2] = y;
    }

    CL(dp,0); CL(vt,false);
    vt[0][0][0][0] = true;

    for (i = 0; i < n; ++i)
    {
        for (j = 0; j <= min(i,m); ++j)
        {
            for (k = 0; k <= i; ++k)
            {
                for (p = 0; p < 3; ++p)
                {
                    if (vt[i][j][k][p])
                    {
                        for (q = 0; q < 3; ++q)
                        {
                            //可以累加
                            if (over(i + 1,q,k,p))
                            {
                                dp[i + 1][j][i + 1][q] = max(dp[i + 1][j][i + 1][q],dp[i][j][k][p] + a[i + 1][q][2]);
                                vt[i + 1][j][i + 1][q] = true;
                            }
                            //另起一堆
                            dp[i + 1][j + 1][i + 1][q] = max(dp[i + 1][j + 1][i + 1][q],dp[i][j][k][p] + a[i + 1][q][2]);
                            vt[i + 1][j + 1][i + 1][q] = true;
                            //直接跳过
                            dp[i + 1][j][k][p] = max(dp[i + 1][j][k][p],dp[i][j][k][p]);
                            vt[i + 1][j][k][p] = true;
//                            printf(">>>>%d %d %d\n",dp[i + 1][j][i + 1][q],dp[i + 1][j + 1][i + 1][q],dp[i + 1][j][k][p]);
                        }
                    }
                }
            }
        }
    }
    int ans = 0;
//    printf("%d %d\n",n,m);
    for (k = 1; k <= n; ++k)
    {
        for (p = 0; p < 3; ++p)
        {
//            printf(">>>>>>%d\n",dp[n][m][k][p]);
            ans = max(ans,dp[n][m][k][p]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

 公路巡逻

思路:

dp[i][j]表示到达在时间为j时第i个关口与巡逻车相遇的最少次数 dp[i + 1][j + 1] = max(dp[i + 1][j + 1],dp[i][j] + s); s表示目标车在 [j, j + k]时间段内从第i个关口出发到i + 1个关口与巡逻车相遇的次数。

其实状态转移很好想,只是在车辆相遇上脑子短路了,我们只要排除不相遇的就好了。

这里还没有优化。。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#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("din", "r", stdin)
#define Write() freopen("dout", "w", stdout);


#define M 86405
#define N 55

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

struct node
{
    int s,e;
}nd[N][N];
int ln[N];


int dp[N][M];
bool vt[N][M];
int n,m;



int main()
{
//    Read();
    int i,j,k;
    int ni,di;
    char ti[7];
    scanf("%d%d",&n,&m);

    CL(ln,0);
    CL(nd,0);
    for (j = 0; j < m; ++j)
    {
        scanf("%d%s%d",&ni,ti,&di);
        int no = 0;   int sum = 0;
        for (i = 0; i < 6; ++i)
        {
            if (i%2 == 1)
            {
                no = no*10 + ti[i] - '0';
                int tmp = 0;
                if (i == 1) tmp = 3600;
                else if (i == 3) tmp = 60;
                else tmp = 1;
                sum += no*tmp;
                no = 0;
            }
            else
            {
                no = no*10 + ti[i] - '0';
            }
        }
        int &p = ln[ni];
        nd[ni][p].s = sum;
        nd[ni][p].e = sum + di;
        p++;
    }

    for (i = 1; i <= n; ++i)
    {
        for (j = 0; j <= 86400; ++j)
        {
            dp[i][j] = inf;
        }
    }

    CL(vt,false); dp[1][21600] = 0;
    vt[1][21600] = true;
    for (i = 1; i < n; ++i)
    {
        for (j = 21600; j <= 51000; ++j)
        {
            if (vt[i][j])
            {
                for (k = 300; k <= 600; ++k)
                {
                    int s = 0;
                    int p;
                    for (p = 0; p < ln[i]; ++p)
                    {
                        if (nd[i][p].e == j + k) s++;
                        else
                        {
                            if (j <= nd[i][p].s && j + k <= nd[i][p].e) continue;
                            if (j >= nd[i][p].s && j + k >= nd[i][p].e) continue;
                            s++;
                        }
                    }
                    dp[i + 1][j + k] = min(dp[i + 1][j + k],dp[i][j] + s);
                    vt[i + 1][j + k] = true;
                }
            }
        }
    }
    int ans = inf;
    int tim = 0;
    for (i = 21600; i <= 51000; ++i)
    {
        if (vt[n][i] && dp[n][i] < ans)
        {
            ans = dp[n][i];
            tim = i;
        }
    }
    int hh = tim/3600;
    tim -= hh*3600;
    int mm = tim/60;
    tim -= mm*60;
    int ss = tim;
    printf("%d\n%02d%02d%02d\n",ans,hh,mm,ss);
    return 0;
}

 

 ===================================================================

 

poj 1337 A Lazy Worker

题意:

一个懒工人,他想工作的时间尽量少。有N个任务,每个任务有开始时间和deadline,工人完成这个工作需要ti时间。如果某个时刻有工作可以做(这里是说,如果从这个时刻开始某个工作,在deadline之前能够完成),那么这个工人必须做,但是如果这个时刻存在着多余1件工作可以做,工人可以选择;假设这个时刻没有工作可以做了,工人就可以偷懒直到有新的任务到来

思路:

刚开始以为只要我一空下来有工作,我就必须从这一点开始工作来着,其实不是的,只要在最晚期限之前完成该工作即可。

dp[i]表示在时间点i时,完成工作所需要的最少时间,dp[i + 1] = min(dp[i + 1],dp[i])当该时间没有工作干时,当有多个工作时,dp[i + tk] = min(dp[i + tk],dp[i] + tk) k表示第k个工作可以再时间点i完成

这里注意inf = 0x3fffffff 因为会有inf的相加,这里快整死我了,给很长时间没有条出来。。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
#include <list>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#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("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 107
#define N 117
using namespace std;

const ll mod = 1000000007;
const int inf = 0x3fffffff;

struct node
{
    int ti,ai,di;
}nd[N];

int dp[260];
vector<int> work[260];

int main()
{
//    Read();
//    printf("%d \n%d\n",0x7fffffff,0x3fffffff);
    int T;
    int i,j;
    int n;
    scanf("%d",&T);

    while (T--)
    {
        scanf("%d",&n);
        int s = inf, e = 0;
        for (i = 0; i < n; ++i)
        {
            scanf("%d%d%d",&nd[i].ti,&nd[i].ai,&nd[i].di);
            s = min(s,nd[i].ai); e = max(e,nd[i].di);
        }
        for (i = s; i <= e; ++i)
        {
            work[i].clear();
            for (j = 0; j < n; ++j)
            {
                if (i >= nd[j].ai && i + nd[j].ti <= nd[j].di)
                {
                    work[i].push_back(j);
                }
            }
        }

        for (i = s; i <= e; ++i) dp[i] = inf;
        dp[s] = 0;
        for (i = s; i < e; ++i)
        {
            if (work[i].size() == 0) dp[i + 1] = min(dp[i + 1],dp[i]);
            else
            {
                int sz = work[i].size();
                for (int j = 0; j < sz; ++j)
                {
                    int k = work[i][j];

                    dp[i + nd[k].ti] = min(dp[i + nd[k].ti],dp[i] + nd[k].ti);
                }
            }
        }
        printf("%d\n",dp[e]);
    }
    return 0;
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值