zoukankan      html  css  js  c++  java
  • POJ1015陪审团(Jury Compromise)——dp+路径记录

    题目:http://poj.org/problem?id=1015

    差值是有后效性的,所以“转化为可行性”,开一维记录“能否达到这个差值”。

    当然可以开两维分别记录 a 和 b,但 “值只是0或1” 和 “当前元素对应一个 a 只有一个 b ,其他 b 就浪费了” 这两点说明这种状态有优化空间。

    开一维记录差值,d数组的值记录最大的 a+b 值较好。

    虽然差值是绝对值,但需要分正负以计算。可以全部加一个修正值 fix 解决脚标非负的问题。(不要试图开一维0或1记录正负,会在边界的地方分类讨论而死)

    然后是重点!!!如何记录路径???

    用了LICS记录路径的自己的那个方法:记一个pre,记一个use。但本题中的意义与那题略有不同。自我感觉还不错。虽然慢到了469ms。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int fix=405;
    int n,m,a[205],b[205],d[25][815],pre[205][25][815],ls,xnt,use[205][25][815];
    void print(int i,int j,int k,int as,int bs)
    {
        if(!j)
        {
            printf("Best jury has value %d for prosecution and value %d for defence:
    ",as,bs);
            return;
        }
        print(pre[i][j][k],j-1,k-(a[i]-b[i]),as+a[i],bs+b[i]);//pre只存了阶段,j和k还得自己传参 
        printf("%d ",i);
    }
    int main()
    {
        while(++xnt)
        {
            scanf("%d%d",&n,&m);
            if(!n&&!m)return 0;
            const int lm=20*m;
            for(int i=1;i<=n;i++)
                scanf("%d%d",&a[i],&b[i]);
            memset(d,-2,sizeof d);
            memset(pre,0,sizeof pre);
            d[0][fix]=0;
            for(int i=1;i<=n;i++)
            {
                memcpy(use[i],use[i-1],sizeof use[i-1]);//如果什么都不做,就是沿用着i-1的值(省去的那一维) 
                memcpy(pre[i],pre[i-1],sizeof pre[i-1]);//pre记录上一步是哪个阶段 
                for(int j=m;j;j--)                            //(对于没有用当前的i的情况,没什么用)
                {
                    int k=a[i]-b[i];
                    for(int l=-lm+fix;l<=lm+fix;l++)
                        if(l-k>=-lm+fix&&l-k<=lm+fix&&d[j-1][l-k]+a[i]+b[i]>d[j][l])
                        {
                            d[j][l]=d[j-1][l-k]+a[i]+b[i];
                            use[i][j][l]=i;//在i这个阶段,达到j和l的是第i号元素 
                            if(use[i-1][j-1][l-k]==i-1)        //第几个阶段就是第几号元素。因第i阶段正在考虑第i号元素 
                                pre[i][j][l]=i-1;
                            else pre[i][j][l]=use[i-1][j-1][l-k];//暨第几阶段 
                        }
                }            //use和pre的分离只是为了那个判断,能在被用的元素处pre停留一下 
            }                //但他们的意义还是有不同的 
                
            for(int i=fix,j=fix;i<=lm+fix&&j>=-lm+fix;i++,j--)
                if(d[m][i]>=0||d[m][j]>=0)
                {
                    if(d[m][i]>=0)ls=i;
                    if(d[m][j]>d[m][i])ls=j;
                    break;
                }
            printf("Jury #%d
    ",xnt);
            if(use[n][m][ls]==n)
            {
                print(pre[n][m][ls],m-1,ls-(a[n]-b[n]),a[n],b[n]);
                printf("%d ",n);
            }
            else print(use[n][m][ls],m,ls,0,0);//不是pre!! 
            printf("
    ");
        }
    }

    然而有100ms左右的方法,还有各种各样的:http://www.cnblogs.com/Zinn/p/8571061.html

    记录路径是一门学问。

  • 相关阅读:
    容器(四)实现容器的底层技术【25】
    容器(四)限制容器的 Block IO【24】
    容器(四)限制容器对CPU的使用【23】
    容器(四)限制容器对内存的使用【22】
    容器(四)一张图搞懂容器所有操作【21】
    容器(四)容器常用操作【20】
    容器(四)运行容器的最佳实践【19】
    容器(四)进入容器的方法【18】
    容器(四) 运行容器方法【17】
    51单片机学习笔记
  • 原文地址:https://www.cnblogs.com/Narh/p/8571114.html
Copyright © 2011-2022 走看看