P3891 [GDOI2014] 采集资源

P3891 [GDOI2014] 采集资源

题目描述

魔兽争霸 3 中,战略资源的采集通过使用农民、苦工、小精灵以及寺僧来进行。

在魔兽争霸 4 的开发中,玻璃渣觉得这种模式太过单一,于是他们想添加更多的单位来使采集的模式更加丰富。

在新的模式中,玩家可以建造更多种类的“苦工”,不同的“苦工”的工作效率不同,同时,建造不同的“苦工”所需要的资源也是不一样的。

玻璃渣出品的游戏以追求平衡著称,所以为了测试这种新的模式的平衡性,他们设计了一套检测的方法:在各种族的起始资源相同时,测量达到某一资源数量的时间,如果相同则可以认为设计是平衡的。

他们将数据给你,希望你能测试出设计是否平衡。

输入格式

第一行三个数,\(N,M,T\),表示苦工的种类、开始时拥有的资源数量以及需要达到的资源的数量。

接下来 \(N\) 行,每行2个数 \(A,B\),表示生产这种苦工所需要的资源,以及这个苦工的效率,效率即为单位时间内产生的资源的数量。

输出格式

一个数字,表示资源数量达到 \(T\) 时的最少时间。

注意:与魔兽争霸 3 不同,魔兽争霸 4 中,生产苦工不需要时间。并且资源的采集并不连续,亦即如果一个苦工的效率为 \(2\),他会在时间为 \(1\) 的时候收获 \(2\) 点资源,而并不会在时间为 \(0.5\) 的时候收获 \(1\) 点资源。

输入输出样例 #1

输入 #1

1 1 8
1 1

输出 #1

4

输入输出样例 #2

输入 #2

2 1 8
1 1
2 8

输出 #2

3

说明/提示

对于 \(30\%\) 的数据,\(N\le 10\)\(M,T \le 300\)

对于 \(100\%\) 的数据,\(N\le 100\)\(M,T \le1000\)\(A,B\le 2^{31}\)

数据保证有解。

思路

这道题的关键量有好几个,有苦工的种类,拥有的资源数,效率,时间。

看一下数据范围盲猜 \(O(NMT)\)

这道题求时间,所以说答案或者状态一定有一维时间,那还有一维大概率是苦工种类。

那么剩下来的一维可以放效率,也可以放资源,这里我使用的是放资源的方法。

\(f_{i,j}\) 表示对于前 \(i\) 类苦工,拥有 \(j\) 的资源所需要的最小时间。

那么就有转移:

\[f_{i,j}= \]

好吧这么写是错的,转移写不出来,因为前 \(i\) 类苦工和拥有 \(j\) 的资源,这两个已知变量不能作为推出新状态值的充分条件,这是不满足最优子结构的。因为拥有 \(j\) 的资源,但并没有记效率这一维,那么 \(f_{i,j}\) 就无法从 \(f_{i-1,k}\) 转移过来,所以状态设计有问题。

那么这样就告诉我们状态中一定要有时间或者效率,因为这样的话对于这个状态下,效率/时间就是定下来的,那么后面的状态对应的值也就能求出来了。

直接设:

\(f_{i,j}\) 表示时间为 \(i\) ,拥有资源为 \(j\) 时的最大效率,然后发现好像用刷表法更好推转移方程

\[f_{i+1,j+f_{i,j}}=\max\{f_{i,j}\} \\ f_{i+1,j-k+g_k}=\max\{f_{i,j}+g_k\} \]

其中 \(g_j\) 指一次性花费 \(j\) 的资源能获得的效率的最大值,用一遍完全背包维护就可以了

code

#include <bits/stdc++.h>
using namespace std;
const int N=110,M=1100;
int n,m,t;
int A[N],B[N];
int f1[N][M],g[M][M],f[M];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>t;
	for(int i=1;i<=n;i++) cin>>A[i]>>B[i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=t;j++){
			if(j>=A[i]) f[j]=max(f[j],f[j-A[i]]+B[i]);
		}
	}
	memset(g,-1,sizeof(g));
	for(int i=0;i<=m;i++) g[0][m-i]=f[i];
	int ans=1e7;
	for(int i=0;i<=t;i++){
		if(g[i][t]!=-1){
			cout<<i;
			return 0;
		}
		for(int j=1;j<=t;j++){
			if(g[i][j]==-1) continue;
			g[i+1][j+g[i][j]]=max(g[i+1][j+g[i][j]],g[i][j]);
			for(int k=1;k<=j;k++){
				if(j-k+g[i][j]+f[k]>=t){
					cout<<i+1;
					return 0;
				}
				g[i+1][j-k+g[i][j]+f[k]]=max(g[i+1][j-k+g[i][j]+f[k]],g[i][j]+f[k]);
			}
			
		}
	}
	

	
	//for(int i=0;i<=t;i++) ans=min(ans,g[t][i]);
	return 0;
}

/*
2 1 8
1 1
2 8

*/
posted @ 2025-07-29 16:26  shencheng4014  阅读(8)  评论(0)    收藏  举报