心如止水
Je n'ai pas le temps
posts - 400,comments - 130,trackbacks - 0

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;
}

posted on 2010-01-06 19:48 lee1r 阅读(668) 评论(1)  编辑 收藏 引用 所属分类: 题目分类:动态规划

FeedBack:
# re: vijos P1313 金明的预算方案 求助
2010-10-06 17:51 | dingdinglhz@gmail.com
//大牛帮帮忙!!!

#include<iostream>
using namespace std;
int c[61],w[61];//原始c、w
int kids[61][2],father[61];//主附件关系
int lc[61][4],lw[61][4];//分组后c、w
int f[3201];
int n,m,fa=0;
void init(){
int k[61];
cin>>n>>m;
for(int i=1;i<=m;i++){cin>>c[i]>>w[i]>>k[i];c[i]/=10;w[i]*=c[i];}
for(int i=1;i<=m;i++){if(!k[i]){fa++;father[fa]=i;}}
for(int i=1;i<=m;i++){
if(k[i]){
if(kids[k[i]][0]){kids[k[i]][1]=i;}
else{kids[k[i]][0]=i;}
}
}
for(int i=1;i<=fa;i++){
cout<<kids[i][0]<<" "<<kids[i][1]<<" "<<father[i]<<endl;
}
}
void make_club(){
for(int i=1;i<=fa;i++){
lc[i][0]=c[father[i]];lw[i][0]=w[father[i]];
lc[i][1]=lc[i][0]+c[kids[i][0]];lw[i][1]=lw[i][0]+w[kids[i][0]];
lc[i][2]=lc[i][0]+c[kids[i][1]];lw[i][2]=lw[i][0]+w[kids[i][1]];
lc[i][3]=lc[i][1]+lc[i][2]-lc[i][0];lw[i][3]=lw[i][1]+lw[i][2]-lw[i][0];
}
for(int i=1;i<=fa;i++){
for(int j=0;j<=3;j++){
cout<<lc[i][j]<<" "<<lw[i][j]<<endl;
}
cout<<endl;
}
}
void dp(){
for(int k=1;k<=fa;k++){
for(int v=(n/10);v>=0;v--){
//for(int v=0;v<=(n/10);v++){
for(int i=0;i<=3;i++){
if(v-lc[k][i]>=0){f[v]=max(f[v],f[v-lc[k][i]]+lw[k][i]);}
}
}
for(int v=0;v<=n/10;v++){cout<<f[v]<<" ";}
cout<<endl;
}
cout<<f[n/10]*10;
}
int main(){
//freopen("budget.in" ,"r",stdin );
//freopen("budget.out","w",stdout);
init();
make_club();
dp();
system("pause");
return 0;
}
/*
自测60分
2000 10
500 1 0
400 4 0
300 5 1
400 5 1
200 5 0
500 4 5
400 4 0
320 2 0
410 3 0
400 3 5
正确答案为7340,我的答案为7200。中间加了几句调试,答案是最后一行;
大牛们帮帮忙!!!
  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理