现在的位置: 首页 > 综合 > 正文

POJ 1179 Polygon 记忆化dfs vs dp

2018年04月25日 ⁄ 综合 ⁄ 共 2887字 ⁄ 字号 评论关闭

题意:给定n(3<=n<=50)边形,每个顶点是一个数字,每条边是一种运算+(t)/ *(x)。
          现在进行一种游戏,分两步:1 破坏掉其中一条边;2 在剩下的n个数字和n-1种运算中规定任意运算顺序,得到最大值,求最大值和对应删点的边的编号。
          运算过程数字的范围为[-32768 , 32767].
题解:因为删掉不同边的时候面对的情况是不同的,所以首先枚举删边,假设第1条边编号为0,连接的是0-n-1顶点,第2条边编号为1,连接的是1-2顶点…
          想到dp[i][j][0](i<=j)代表[i , j]闭区间顺时针方向得到的最大值,dp[i][j][1](i<=j)代表[i , j]闭区间逆时针方向得到的最大值。
          由于dp过程较复杂,我用记忆化dfs处理。需要记录dp[i][j][k](i<=j , 0<=k<=1)的最小值和最大值(记录最小值的原因见如下数据),
          然后枚举最后一次运算的位置,更新当前的最大值和最小值。
/*
5
t -1 t -2 x -2 t -3 t -2
ans:
25
5
*/
PS:这个题的输出格式很二逼,只在答案边的编号之间printf(" ");会pe,要在每一个答案边的编号之后printf(" ");才ac,唉…

简单说说记忆化dfs和dp的关系:
首先记忆化dfs和dp是解决同一类问题,即当前问题可由若干子问题合并解决,即所谓的dp方程;dp是从小问题->大问题的方向解决的过程,记忆化dfs是从大问题->小问题的方向解决的过程,这样很容易看到,dp的过程需要明确的dp方程,而记忆化dfs的过程对dp方程的概念不是那么明确(额…个人认为),值需要认清楚一个大问题的子问题并能够正确从子问题中得到大问题的解决方法即可;如果dp方程很容易写出,还是dp比较好,这样很容易估计时间复杂度,如果对大问题的子问题认识的很清楚,记忆化dfs很容易上手。

Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int maxn = 52;
int dpmax[maxn][maxn][2],dpmin[maxn][maxn][2],num[maxn],edge[maxn];
bool vis[maxn][maxn][2];
int n;

inline int MAX(int a,int b)
{
    return a > b ? a : b;
}

inline int MIN(int a,int b)
{
    return a < b ? a : b;
}

void read()
{
    memset(vis,false,sizeof(vis));
    char str[3];
    for(int i=0;i<n;i++)
    {
        scanf("%s %d",str,&num[i]);
        if(str[0] == 't') edge[i] = 0;
        else edge[i] = 1;
    }
    return;
}

int dfs(int st,int to,int d)
{
    if(vis[st][to][d])
    {
        return dpmax[st][to][d];
    }
    if(st == to)
    {
        vis[st][to][d] = true;
        return dpmax[st][to][d] = dpmin[st][to][d] = num[st];
    }
    if(d == 0)
    {
        bool flag = false;
        int resma , resmi;
        for(int i=st;i<to;i++)
        {
            int le = dfs(st , i , 0);
            int ll = dpmin[st][i][0];
            int ri = dfs(i+1 , to , 0);
            int rr = dpmin[i+1][to][0];

            int addma = MAX(MAX(le + ri , le + rr) , MAX(ll + ri , ll + rr));
            int mulma = MAX(MAX(le * ri , le * rr) , MAX(ll * ri , ll * rr));

            int addmi = MIN(MIN(le + ri , le + rr) , MIN(ll + ri , ll + rr));
            int mulmi = MIN(MIN(le * ri , le * rr) , MIN(ll * ri , ll * rr));

            int tma = edge[i+1] ? mulma : addma;
            int tmi = edge[i+1] ? mulmi : addmi;
            if(flag == false)
            {
                flag = true;
                resma = tma;
                resmi = tmi;
            }
            else
            {
                resma = MAX(resma , tma);
                resmi = MIN(resmi , tmi);
            }
        }
        vis[st][to][d] = true;
        dpmin[st][to][d] = resmi;
        return dpmax[st][to][d] = resma;
    }
    else
    {
        bool flag = false;
        int resma , resmi , le , ri , ll , rr;
        for(int i=st;i != to;)
        {
            int j = (i - 1 + n) % n;
            if(i <= st)
            {
                le = dfs(i , st , 0);
                ll = dpmin[i][st][0];
            }
            else
            {
                le = dfs(st , i , 1);
                ll = dpmin[st][i][1];
            }

            if(j >= to)
            {
                ri = dfs(to , j , 0);
                rr = dpmin[to][j][0];
            }
            else
            {
                ri = dfs(j , to , 1);
                rr = dpmin[j][to][1];
            }
            int addma = MAX(MAX(le + ri , le + rr) , MAX(ll + ri , ll + rr));
            int mulma = MAX(MAX(le * ri , le * rr) , MAX(ll * ri , ll * rr));

            int addmi = MIN(MIN(le + ri , le + rr) , MIN(ll + ri , ll + rr));
            int mulmi = MIN(MIN(le * ri , le * rr) , MIN(ll * ri , ll * rr));

            int tma = edge[i] ? mulma : addma;
            int tmi = edge[i] ? mulmi : addmi;
            if(flag == false)
            {
                flag = true;
                resma = tma;
                resmi = tmi;
            }
            else
            {
                resma = MAX(resma , tma);
                resmi = MIN(resmi , tmi);
            }
            i = j;
        }
        vis[st][to][d] = true;
        dpmin[st][to][d] = resmi;
        return dpmax[st][to][d] = resma;
    }
}

void solve()
{
    int res = dfs(0 , n-1 , 0);
    for(int i=0;i<n-1;i++)
    {
        res = MAX(res , dfs(i , i+1 , 1));
    }
    printf("%d\n",res);
    bool flag = false;
    if(dpmax[0][n-1][0] == res)
    {
        printf("1 ");
    }
    for(int i=0;i<n-1;i++)
    {
        if(dpmax[i][i+1][1] == res)
        {
            printf("%d ",i+2);
        }
    }
    printf("\n");
    return;
}

int main()
{
    while(~scanf("%d",&n))
    {
        read();
        solve();
    }
    return 0;
}

抱歉!评论已关闭.