我们可以分情况考虑
我们可以把他当成一个\(01\)背包,背包总体积为m,每个城堡为每一件物品,他的价值为 \(i\) 及他的编号,他的体积为 \(2*\) 派兵的人数加一(保证严格大于其他玩家派兵的人数)。这样跑一遍\(01\)背包不就完事了吗 QAQ。。。。
这样你就会拿到 40-50pts。但作为蒟蒻的我,已经很满足了。。。
2.其他情况,不会写QAQ。。。
附上 40-50pts 代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,s,v;
int f[20010],c[110][110],w[110][110];
void slove2()
{
for(int i = 1; i <=s; i++)//枚举人数
{
for(int j = 1; j <= n; j++)//枚举城堡数
{
scanf("%d",&v);
c[j][i] = 2*v+1;
w[j][i] = j;
}
}
for(int i = 1; i <= n; i++)//01背包
{
for(int j = m; j >= 0; j--)
{
f[j] = f[j-c[i][k]] + w[i][k];
}
}
if(s == 1) printf("%d\n",f[m]);
}
int main()
{
scanf("%d%d%d",&s,&n,&m);
slove2();
return 0;
}
但在经过神犇指导后,我思考出这样一个优化。
当我们往一个城堡派兵数量为 \(v\)时,那么小于\(v\)的其他人都会被打败,也就是出兵比我们少的,都会的打败。假设出兵比我们少的人为 \(p\) 那么你就可以获得 \(i\) * \(p\) 的分数。\(i\)为城堡编号。
我们可以通过排序加快这一过程,这样我们得到了每件物品的价值和体积。
但这时不再是个\(01\)背包,而是个分组背包。我们可以把每个城堡当做一组,
每个城堡,你可以放s种选择,来打败玩家,但每种选择只能选一种。
这不就是个妥妥的分组背包了吗???
综上,这个题的大体思路就是,通过派兵人数从大到小排序处理出每件物品的价值和体积。 物品的体积就是\(2*\)派兵人数+\(1\) 价值就是 \(i*\) 比他小的数的个数(因为排序保证前边的出兵人数都是比他小的)。最后跑一遍分组背包,就可以轻松AC了这道题。
附上AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,s,v;
int f[20010],c[110][110],w[110][110];
int main()
{
scanf("%d%d%d",&s,&n,&m);
for(int i = 1; i <=s; i++)
{
for(int j = 1; j <= n; j++)
{
scanf("%d",&c[j][i]);
}
}
for(int i = 1; i <= n; i++)
{
sort(c[i]+1,c[i]+s+1);//按出兵人数排序
for(int j = 1; j <= s; j++)
{
c[i][j] = c[i][j] * 2 + 1;
w[i][j] = i * j;//他的价值为在这个城堡比他派兵少的人数*这个城堡的编号
}
}
for(int i = 1; i <= n; i++)//分组背包的模板
{
for(int j = m; j >= 0; j--)
{
for(int k = 1; k <= s; k++)
{
if(j - c[i][k] >= 0)
{
f[j] = max(f[j],f[j-c[i][k]] + w[i][k]);
}
}
}
}
printf("%d\n",f[m]);
return 0;
}
本人码风过丑,请各位大佬不要喷QAQ。。。
由于作者是个菜鸡,可能无法解释清楚这道题,请见谅。。。。。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章