Gold miner 分组背包
题意:
要求在T时间内取N件物品,每种物品有其时间价值。
同一条线上的必须依次取。
算法:
刚开始用树形DP做,也就是依赖背包。。TLE。
而且跟据题目要求,必须节点取了,其子节点才能取。
除了TLE,我的限定条件感觉对错也没有太大把握,
做题时一定要正确选择算法,分析算法可行性(正确性,时间上,内存上),不要浪费时间。
超时的树形DP:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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) 编辑 收藏 举报