poj-2979-陪审团的人选-C语言-动态规划
2017-06-10 17:04
387 查看
算法丑陋,时间略长,还望指教。
#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
[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;
}
#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
[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;
}
相关文章推荐
- POJ 2979 陪审团的人选 解题报告
- POJ 1015 陪审团人选 [动态规划]
- POJ 1015 公正陪审团问题 动态规划
- Jury Compromise(陪审团的人选、动态规划题)
- ACM POJ 1015 Jury Compromise(陪审团的人选,动态规划题,难)
- poj-2806-公共子序列-C语言-动态规划
- OpenJudge 2979 陪审团的人选 / Poj 1015 Jury Compromise
- POJ 1015 公正陪审团问题 动态规划
- OpenJudge 2979 陪审团的人选 / Poj 1015 Jury Compromise
- poj 1221 UNIMODAL PALINDROMIC DECOMPOSITIONS 动态规划
- POJ 3267-The Cow Lexicon 动态规划
- poj 2411 动态规划
- POJ 2533-Longest Ordered Subsequence 动态规划
- POJ 2479(动态规划) [求最大子段和 的延伸]
- POJ 2411 Mondriaan's Dream 解题报告【动态规划】(代码部分)
- Poj 1157(动态规划)
- POJ 1661 Help Jimmy(动态规划)
- 动态规划(线性模型):POJ 2533 最长上升子序列
- POJ 1260-Pearls 动态规划
- POJ 2533 Longest Ordered Subsequence(DP动态规划)