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\) 的资源所需要的最小时间。
那么就有转移:
好吧这么写是错的,转移写不出来,因为前 \(i\) 类苦工和拥有 \(j\) 的资源,这两个已知变量不能作为推出新状态值的充分条件,这是不满足最优子结构的。因为拥有 \(j\) 的资源,但并没有记效率这一维,那么 \(f_{i,j}\) 就无法从 \(f_{i-1,k}\) 转移过来,所以状态设计有问题。
那么这样就告诉我们状态中一定要有时间或者效率,因为这样的话对于这个状态下,效率/时间就是定下来的,那么后面的状态对应的值也就能求出来了。
直接设:
\(f_{i,j}\) 表示时间为 \(i\) ,拥有资源为 \(j\) 时的最大效率,然后发现好像用刷表法更好推转移方程
其中 \(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
*/

浙公网安备 33010602011771号