POJ 1015 陪审团人选 [动态规划]

来源:互联网 发布:成都和重庆公务员知乎 编辑:程序博客网 时间:2024/05/21 17:16

   动态规划太深奥了,太难规了,这题又是看《程序设计引导及在线实践》上面的思路和代码做的,具体规划思路如下:

 

     用f[i][j]表示,取i个候选人,使其辩控差为j 的所有方案中,辩控和最大的那个方案的控辩和。

要求f[i][j] 显然要从一个可行的方案 f[i-1][x] 演化而来。可行方案f(i-1, x)能演化成方案f(j, k)的必要条件是:

存在某个候选人k,k 在方案f(i-1, x)中没有被选上,且x+V(k) = j;(V(k)为第k个人的控辩差);

选出 f(i-1, x) + S(k)(控辩和)  的值最大的那个,那么方案f(i-1, x)再加上候选人k,就演变成了方案 f(i, j)。

这中间需要将一个方案都选了哪些人都记录下来。不妨将方案f(i, j)中最后选的那个候选人的编号,记在二维

数组的元素path[i][j]中。那么方案f(i, j)的倒数第二个人选的编号,就是path[i-1][j-V[path[i][j]]。

假定最后算出了解方案的辩控差是k,那么从path[m][k]出发,就能顺藤摸瓜一步步求出所有被选中的候选人。

#include <stdio.h>#include <math.h>#include <string.h>#include <stdlib.h>int compare(void const* a, void const* b){    return *(int*)a - *(int*)b;}int main(){    int n, m, i, j, k, t1, t2, casenum=1, min;    int f[21][1000], p[201], d[201], path[21][1000];    int Qnum[21], Q[21][900]; //队列    int ans[21];    while (scanf("%d %d", &n, &m) && n)    {        memset(f, -1, sizeof(f));   //这样也行!!赋值之后是-1;为什么呢???        memset(Qnum, 0, sizeof(Qnum));        for (i=1; i<=n; i++)        {            scanf("%d %d", &p[i], &d[i]);        }        Q[0][0] = 400;        Qnum[0] = 1;        f[0][400] = 0;        for (i=0; i<m; i++)        {            for (j=0; j<Qnum[i]; j++)            {                for (k=1; k<=n; k++)                {                    if(f[i][Q[i][j]]+p[k]+d[k] > f[i+1][Q[i][j]+p[k]-d[k]])                    {                        t1 = i;        //以下检验k是否已经在f[i][Q[i][j]]中被选上                        t2 = Q[i][j];                        while (t1>0 && path[t1][t2]!=k)                        {                            t2 -= p[path[t1][t2]]-d[path[t1][t2]];                            t1--;                        }                        if (t1==0) //没有被选上,可选                        {                            if (f[i+1][Q[i][j]+p[k]-d[k]] == -1)                            {    //添加到队列                                Q[i+1][Qnum[i+1]] = Q[i][j]+p[k]-d[k];                                Qnum[i+1]++;                            }                            f[i+1][Q[i][j]+p[k]-d[k]] = f[i][Q[i][j]]+p[k]+d[k];                            path[i+1][Q[i][j]+p[k]-d[k]] = k;                        }                    }                }            }        }        min = 900;       //计算控方和辩方差值的绝对值最小值        for (i=0; i<Qnum[m]; i++)        {            if (abs(Q[m][i]-400) < min) min = abs(Q[m][i]-400);        }        if (f[m][400+min] > f[m][400-min]) min = min+400;  //选最小差值中总分和最大的        else min = 400-min;        printf("Jury #%d\n", casenum++);        printf("Best jury has value %d for prosecution and value %d for defence:\n",                                  (min-400+f[m][min])/2, (400-min+f[m][min])/2);        for (i=0; i<m; i++) //从后往前依次找被选中的m个人        {            ans[i] = path[m-i][min];            min -= p[ans[i]]-d[ans[i]];        }        qsort(ans, m, sizeof(int), compare);        for (i=0; i<m; i++)          printf(" %d", ans[i]);        printf("\n\n");    }}


原创粉丝点击