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

poj1015

2013年09月03日 ⁄ 综合 ⁄ 共 1731字 ⁄ 字号 评论关闭

题目分析:

首先我们用f[m,n]表示有m个候选人差值为n的最大的和。解释一下,已知辩护和反辩的值为d[i],j[i],那么差值就是d[i]-j[i],和就是d[i]+j[i].而这里的差值是选了要求的候选人的差值和和。

 

那么递推式是什么呢?不妨从f[m-1][t]->f[m][n],那么这两个之间的关系是什么呢,对于所有的t+d[i]-j[i]==k的最大的f[m-1][t]+d[i]+j[i].既是f[m][n]=max(f[m-1][t]+d[i]+j[i])当t+d[i]-j[i]==k的时候。注意:差值可能有负数,我们可以将所有的值同时加上一个数。

对于记录那几个候选人,就是通过顺藤摸瓜的方法,这个方法在很多算法中用过。

对于最后一个我们记做f[m][n]=i;怎么找钱一个呢?前一个就是f[m-1][n-d[i]+j[i]].注意结果要求有序,要排序,不知道为什么sort不行,只好用qsort了。

#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<cstring>
#include<algorithm>
using namespace std;

int dp[21][801],path[21][801];
int D[201],J[201],res[21];

int cmp(const void *a,const void *b)
{
 return *(int*)a-*(int*)b;
}
bool select(int a,int b,int i){
    while(a>0 && path[a][b]!=i){
        b-=D[path[a][b]]-J[path[a][b]];
        a--;
    }
    return (a!=0)?true:false;//i有没有被用过。
}

int main()
{
 int i,j,k,r,n,m,cnt=1,a,b;
 while(scanf("%d%d",&n,&m),n||m)
 {
  for(i=1;i<=n;i++)
  {
   scanf("%d%d",&D[i],&J[i]);
  }
  memset(dp,-1,sizeof(dp));
  memset(path,0,sizeof(path));
  r=m*20;
  dp[0][r]=0;
  for(j=0;j<m;j++)
  {
   
   for(k=0;k<=r*2;k++)
   {
    if(dp[j][k]>=0)
    {
     for(i=1;i<=n;i++)
     {
      if(dp[j+1][k+D[i]-J[i]]<dp[j][k]+D[i]+J[i])//状态方程
      {
       a=j;
       b=k;
       if(!select(a,b,i))
       {
        dp[j+1][k+D[i]-J[i]]=dp[j][k]+D[i]+J[i];
        path[j+1][k+D[i]-J[i]]=i;
       }
      }
     }
    }
   }
  }
  for(i=r,j=0;dp[m][i+j]<0&&dp[m][i-j]<0;j++);//寻找绝对值最小的
  k=dp[m][i+j]>dp[m][i-j]?i+j:i-j;//寻找绝对值最小的和最大的
  printf("Jury #%d/n",cnt++);
        printf("Best jury has value %d for prosecution and value %d for defence:/n",(dp[m][k]+k-r)/2, (dp[m][k]-k+r)/2);
  for(i=1;i<=m;i++)
  {
   res[i]=path[m-i+1][k];
   k-=D[res[i]]-J[res[i]];
  }
  qsort(res+1,m,sizeof(res[0]),cmp);
  for(i=1;i<=m;i++)
   printf(" %d",res[i]);
  printf("/n/n");
 }
 return 0;
}

 

 

抱歉!评论已关闭.