vijos P1313 金明的预算方案

vijos P1313 金明的预算方案

NOIp2006年的第二题,典型的动态规划,物品之间有依赖关系。可以把物品分为若干组,每组最多有四种衍生出来的“物品”,即只选择一个主件,选择一个主件和一个附件(两种),选择一个主件和两个附件。由题意得,每组只能选择一个“物品”,这样就把题目转化成了分组背包问题。

我的做法是DFS一次(虽说是DFS,实际结点数只是4),计算出衍生出来的若干组“物品”,然后用分组背包的做法进行动态规划。

此题目还有一个优化:因为所给数据是10的倍数,所以可以在开始时除以10,最后输出时再乘上10,用来减少状态数量。

 

以下是我的代码:

#include < stdio.h >
#define  SIZE 61
#define  max(a,b) (a>b?a:b)
long  N,m,v[SIZE],p[SIZE],q[SIZE];
long  maino = 0 ,c[SIZE][SIZE] = {0} ,w[SIZE][SIZE] = {0} ,d[ 3201 ] = {0} ;
int  find( int  nn, int  kk)
{
    
long i;
    
for(i=kk;i<=m;i++)
      
if(q[i]==nn)
         
return i;
    
return 0;
}

void  dfs( long  now, long  ii, long  weight, long  cost)
{// 第now个主件 
    long t;
    t
=find(now,ii+1);
    
if(!t)
    
{
       c[maino][
0]++;
       w[maino][
0]++;
       c[maino][ c[maino][
0] ]=cost;
       w[maino][ w[maino][
0] ]=weight;
       
return;
    }

    dfs(now,t,weight,cost);
    dfs(now,t,weight
+v[t]*p[t],cost+v[t]);
}

void  init()
{
    
long i,j;
    FILE 
*fin=fopen("budget.in","r");
    fscanf(fin,
"%ld%ld",&N,&m);
    N
/=10;
    
for(i=1;i<=m;i++)
      q[i]
=0;// Clear
    for(i=1;i<=m;i++)
    
{
       fscanf(fin,
"%ld%ld%ld",&v[i],&p[i],&q[i]);
       v[i]
/=10;
    }

    fclose(fin);
    
// Read In
    for(i=1;i<=m;i++)
    
{
       c[i][
0]=0;
       w[i][
0]=0;
    }

    
for(i=1;i<=m;i++)
      
if(q[i]==0)
      
{
         maino
++;
         dfs(i,
0,v[i]*p[i],v[i]);
      }

}

void  dp()
{
    
long k,i,j;
    
for(k=1;k<=maino;k++)
      
for(j=N;j>=0;j--)
        
for(i=1;i<=c[k][0];i++)
          
if(j>=c[k][i])
            d[j]
=max(d[j],d[j-c[k][i]]+w[k][i]);
}

void  write()
{
    FILE 
*fout=fopen("budget.out","w");
    
long i,ans=0;
      
for(i=0;i<=N;i++)
        ans
=max(ans,d[i]);
    fprintf(fout,
"%ld\n",ans*10);
    fclose(fout);
}

int  main()
{
    init();
    dp();
    write();
return 0;
}

你可能感兴趣的:(vijos P1313 金明的预算方案)