poj-2979-陪审团的人选-C语言-动态规划

本文通过C语言实现POJ-2979题目的解法,利用动态规划策略解决陪审团人选问题。虽然算法表达不够优雅,运行时间稍长,欢迎探讨优化方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法丑陋,时间略长,还望指教。

#include <stdio.h>
#include <memory.h>
/*
第一步,读懂题意,题目的要求是使得选定方案,在辩控差最小的前提下,辩控和最大。
第二步,寻找状态,这道题的状态有两个比较关键的点,一是选了多少人,二是这些人的辩控差,如果我们知道已经选出m人时所有组合
的辩控差,从中选取一个是很容易的。所以我们把每个组合的状态记为(选取人数,辩控差)|——>辩控和,并用一个m*m*20*2的数组对状态
进行记录,而且还要考虑到一个状态可能没有对应的人数,而且还要记录具体是选取了那些人,所以我们规定不存在的状态对应辩控和为
-1,再用一个m*m*20*2的数组记录具体的人选。
第三步,状态转移,每次要再选一个人进来,怎么知道这个人到底能不能选呢?如果加入这个人之后,使我们对应状态的辩控和更大,那么
我们认为这是一个更优解。
这里如何避免重复选择也是一个问题,如果直接记录是非常不方便的,所以我们可以记录选择的过程,逆推选择了那些人
*/
int state[21][900],choise[21][900],times,answer[20];
int main()
{
    int n,m,i,j,k,a;
    scanf("%d%d",&n,&m);
    while(n)
    {
        int middleline=m*21;
        times++;
        memset(state,-1,sizeof(state));
        memset(choise,-1,sizeof(choise));
        int score[n][4];//记录每位候选人的状态
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&score[i][0],&score[i][1]);
            score[i][2]=score[i][0]+score[i][1];
            score[i][3]=score[i][0]-score[i][1];
        }
        if(n>m)
        {
            state[0][middleline]=0;//起步状态,一个人都没有选,辩控和当然是0;
            for(i=0;i<m;i++)//对各种可能的总人数情况进行枚举//从0开始向上递推
            {
                for(j=0;j<m*21*2+1;j++)//对某一人数对应的辩控差进行枚举
                {
                    if(state[i][j]>=0)//之前有基础
                    {
                        for(k=0;k<n;k++)//对所有可能的人选进行枚举
                        {
                            if(state[i][j]+score[k][2]>state[i+1][j+score[k][3]])//如果k这个人是符合条件的
                            {
                                int pathfinder=j,flag=1;//当前的辩控差
                                for(a=i;a>0;a--)//还要保证在这一辩控差的条件下,前面不能出现过这个人
                                    (choise[a][pathfinder]==k)?(flag=0):(pathfinder-=score[choise[a][pathfinder]][3]); //逆推的关键步骤
                                if(flag)
                                {
                                    state[i+1][j+score[k][3]]=state[i][j]+score[k][2];
                                    choise[i+1][j+score[k][3]]=k;
                                }
                            }
                        }
                    }
                }
            }//到这里我们已经得到了所有的可行方案
            for(i=0;i<m*21;i++)
            {
                if(state[m][middleline+i]<0&&state[m][middleline-i]<0);
                else
                {
                    (state[m][middleline+i]>state[m][middleline-i])?(a=middleline+i):(a=middleline-i);//这个a就是最后确定的最小辩控和
                    break;
                }
            }
            int b=m,c=a;
            for(i=0;i<m;i++)
            {
                answer[i]=choise[b][c];
                c-=score[choise[b][c]][3];
                b--;
            }
            for(i=0;i<m;i++)
            {
                for(b=0;b<m-i-1;b++)
                {
                    if(answer[b]>answer[b+1])
                    {
                        c=answer[b];
                        answer[b]=answer[b+1];
                        answer[b+1]=c;
                    }
                }
            }
            printf("Jury #%d\n",times);
            printf("Best jury has value %d for prosecution and value %d for defence:\n",(a-middleline+state[m][a])/2,(state[m][a]-a+middleline)/2);
            for(i=0;i<m;i++)
                printf(" %d",answer[i]+1);
        }
        else
        {
            for(i=0,a=0,j=0;i<n;i++)
            {
                a+=score[i][0];
                j+=score[i][1];
            }
            printf("Jury #%d\n",times);
            printf("Best jury has value %d for prosecution and value %d for defence:\n",a,j);
            for(i=0;i<m;i++)
                printf(" %d",i+1);
        }
        printf("\n");
        printf("\n");
        scanf("%d %d",&n,&m);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值