10月4日备战Noip2018模拟赛5(B组)T2 Tree 采果子

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/MOMING_V/article/details/82940548

10月4日备战Noip2018模拟赛5(B组)

T2 Tree 采果子

题目描述

 Lyl大牛今天心情不错,于是走到埃及郊外旅游。他边走边向四周望望,发现周围有许多果树。这些树之间互相到达的时间Lyl是知道的(假定每两棵树之间都拥有独立的边可以到达)。他数出了这些果树上果子的个数,并且估了估每个的价格(真是个奇怪的人)。Lyl规定了一种采摘方案,就是对于第i棵树来说,它有a[i]个果子,且所有果子价值为s[i],摘取时间为c[i](小时)。并且,当他摘了第i个树上的果子后,后面他所选择去摘的果树上的果子数必须大于第i棵树上的果子数目,说白了就是一个上升序列;并且每到一棵树,他都必须摘下该树上的所有果子。一开始,Lyl可以在任意一棵树,他只有m小时,那么,在他所拥有的限定时间内,他想知道,这样摘取的最大价值是多少?

输入格式

输入文件tree.in第一行2个数:n(表示这条路上的大树数),m(总共时间)

    接下来第n+1行,每行三个数a[i],s[i],c[i] (第i+1行输入的为第i颗果树的信息)

    且保证有1<=a[i]<=2^31-1;1<=s[1]+s[2]+…+s[n]<=2^31-1;s[i]>=0; 1<=c[i]<=100

    接下来的n行,每行n个数,第i行第j个数表示从树i到树j的时间。(0<=T[I,j]<=100;)

输出格式

输出文件tree.out有且仅有一个数,即按这样方法摘取的最大价值。

输入样例

4 10
1 10 2
2 5 3
3 6 1
4 9 4
0 1 2 3
1 0 3 4
2 3 0 5
3 4 5 0

输出样例

21

样例解释

先摘第1棵树上的,再摘第2棵树上的,然后第3棵树上的

数据范围

 对于60%的数据 ,1<=N<=60,1<=m<=100;

对于100%的数据 ,1<=N<=100, 1<=m<=1000。

其实考模拟赛的时候,题面改了一下,因为太皮了,所以贴了原题

看到了美味程度(价值),  采摘时间(重量), 很容易看出这道题其实就是01背包, 但是与传统的01背包不同的是,:

扫描二维码关注公众号,回复: 3723159 查看本文章
  1. 因为两棵苹果树之前有距离, 需要耗费时间来走, 那么多加一层循环来找前面采摘的苹果就可以了, f[i][j]表示在ih,第i棵苹果树所采摘苹果的最大美味程度
  2. 因为每次采摘的苹果要比上一次多,所以可以先sort一遍,但是要注意此时的苹果树的编号改变了,那么和邻接矩阵的对应也改变了,所以在struct中加一个no来储存苹果树原来的编号

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 101;
const int M = 1005;

struct Node{
	int apple;
	int delicious;
	int pick;
	int no;             //记录苹果树的编号
}a[N];

int n, m, i, j, r, app, del, pic, Max;
int f[M][N], adj[N][N];

bool cmp (Node a, Node b)
{
	return a.apple < b.apple;
}

int main ()
{
	freopen ("tree.in", "r", stdin);
	freopen ("tree.out", "w", stdout);
	
	scanf ("%d %d", & n, & m);
	for (i = 1; i <= n; i ++){
		scanf ("%d %d %d", & app, & del, & pic);
		a[i].apple = app;
		a[i].delicious = del;
		a[i].pick = pic;
		a[i].no = i;
	}
	for (i = 1; i <= n; i ++){
		for (j = 1; j <= n; j ++){
			scanf ("%d", & adj[i][j]);            
		}
	}
	
	sort (a + 1, a + 1 + n, cmp);            //按苹果数排序
	
	for (i = 1; i <= n; i  ++){
		f[a[i].pick][i] = a[i].delicious;            //每棵树耗费自己的采摘时间可以得到的美味值
	}
	
	for (i = 1; i <= n; i ++){
		for (j = 1; j <= m; j ++){
			f[j][i] = max (f[j][i], f[j - 1][i]);
			for (r = 1; r < i; r ++){            //和传统01背包不同的地方,找上一棵树
				if (j - adj[a[r].no][a[i].no] - a[i].pick >= 0 
					&& a[i].apple != a[r].apple){
						f[j][i] = max (f[j][i], f[j - adj[a[r].no][a[i].no] - a[i].pick][r] + a[i].delicious);
					}
			}
		}
	}
	
	Max = 0;
	for (i = 1; i <= n; i ++){
		Max = max (Max, f[m][i]);            //不确定到第几棵树的最大,从第一颗树开始找一遍
	}
	
	printf ("%d", Max);	
	
	fclose (stdin);
	fclose (stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/MOMING_V/article/details/82940548
今日推荐