Gold miner 分组背包

题意:

要求在T时间内取N件物品,每种物品有其时间价值。

同一条线上的必须依次取。

算法:

刚开始用树形DP做,也就是依赖背包。。TLE。

而且跟据题目要求,必须节点取了,其子节点才能取。

除了TLE,我的限定条件感觉对错也没有太大把握,

做题时一定要正确选择算法,分析算法可行性(正确性,时间上,内存上),不要浪费时间。

超时的树形DP:

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

int N, T;
struct point
{
 int x, y;
 int t, v;
 bool operator < (const point &A) const 
 {
    return abs(x) < abs(A.x);     
 }
}p[300];

int mp[210][210];
int dp[210][210];
int visit[210];

void dfs(int v)
{
     visit[v]=1;
     for(int i = 1;i<= N;i++)
     {
             if( !visit[i] && mp[v][i] )
             {
                if( p[i].t <= T )
                dfs( i );
             }
            else
               continue;  
             for(int j= T; j>=1;j--)
             {
                for(int k = 1;k < j;k++)
                {
                  //if( dp[i][k]!= 0 && dp[v][j-k] != 0 )
                 // {
                     if( j - k >= p[v].t )
                     {
                      dp[v][j-k] = p[v].v;
                      dp[v][j] = max(dp[v][j],dp[i][k]+dp[v][j-k]);
                     }
                     else
                     break;
                  //}
                }
             }
     }
   //  printf("v = %d t = %d v = %d\n",v, p[v].t, p[v].v);
     dp[v][p[v].t] = p[v].v;
     
     
}

int main( )
{
  int abc = 1;
  while( scanf("%d%d",&N,&T) != EOF)
  {
     for( int i = 1; i <= N; i++)
     {
         scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].t,&p[i].v);  
          
     }
     sort(p + 1, p + N + 1);
     memset(visit,0,sizeof(visit));
     memset(mp, 0, sizeof(mp));
     //判断是否共线 
     for( int i = 1; i <= N; i++)
     {
        int x = p[i].x, y = p[i].y;
        if( !visit[i] )
        mp[0][i] = 1;
        for( int j = i + 1; j <= N; j++)  
        {
           int x1 = p[j].x;
           int y1 = p[j].y;
           if( x*y1 == x1 * y )
           {
              mp[i][j] = 1;   
              visit[j] = 1;
                           
           }
             
        }     
     }
     memset(dp,0,sizeof(dp));
     for( int i = 1; i <= N; i++)
     { 
        dp[i][0] = 0;
        if( mp[0][i] )
            dp[i][p[i].t] = p[i].v;
              
     }
     memset(visit,0,sizeof(visit));
     dfs( 0 );
     printf("Case %d: %d\n",abc++,dp[0][T]);
     
  }      
  return 0;
}

正确解法:

分组背包,在每一条线上的物品看作一组,每组可以按顺序取一件,两件,。。。

编程不仔细贡献了好几次WA。

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

int N, T;
struct point
{
 int x, y;
 int t, v;
 bool operator < (const point &A) const 
 {
    return abs(x) < abs(A.x);     
 }
}p[300];


int visit[210];
struct node
{
  int v[210]; //第几个点
}Line[210];

int num[210];

struct pnode
{
int weight[210];
int price[210];
}px[210];

int f[41000];
int cnt;

int solve()
{
   for(int i = 0 ; i<= T ;i++)        //表示背包中可以不需要装满 
      f[i] = 0 ;
    
    for(int k = 0; k < cnt ;k++)  
    {
      for(int v = T ; v >= 0 ;v--) //将每一个分组当做一次01背包 ,故计算顺序为V递减 
       {
         for(int i = 0 ; i < num[k] ;i++)     //针对每一个分组中的每一个i 
         {
           if(v - px[k].weight[i] >= 0)
            f[v] = max(f[v] , f[v - px[k].weight[i]] + px[k].price[i]) ;       
         }   
       }
    }   
    return f[T] ;
 }

int main( )
{
  int abc = 1;
  while( scanf("%d%d",&N,&T) != EOF)
  {
     for( int i = 1; i <= N; i++)
     {
         scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].t,&p[i].v);  
          
     }
     cnt = 0;
     sort(p + 1, p + N + 1);
     memset(visit,0,sizeof(visit));
     memset(num,0,sizeof(num));
     memset(px,0,sizeof(px));
     //判断是否共线 
     for( int i = 1; i <= N; i++)
     {
        int x = p[i].x, y = p[i].y;
        int ff = 0;
        if( !visit[i] )
        {
          Line[cnt].v[num[cnt]++] = i;
          ff = 1;
        }
        else
          continue;
        for( int j = i + 1; j <= N; j++)  
        {
           int x1 = p[j].x;
           int y1 = p[j].y;
           if( x*y1 == x1 * y )
           {
              visit[j] = 1;
              Line[cnt].v[num[cnt]++] = j;    
           }
           
        }
        if( ff )
        cnt++;     
     }
     for( int i = 0; i < cnt; i++)
     {
        int a = 0, b = 0;
        for( int j = 0; j < num[i]; j++)
        {
           int temp = Line[i].v[j];
           a += p[temp].t;
           b += p[temp].v;
           px[i].weight[j] = a;
           px[i].price[j]  = b;
          // printf("a = %d b = %d\n",a,b);
        }     
          
     }
     printf("Case %d: %d\n",abc++,solve( ));
     
  }      
  return 0;
}

 

 

posted on 2012-08-07 18:06  more think, more gains  阅读(240)  评论(0编辑  收藏  举报

导航