P5322 排兵布阵

题意描述:

洛谷

小 C 正在玩一款排兵布阵的游戏。在游戏中有 \(n\) 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 \(m\) 名士兵,可以向第 \(i\) 座城堡派遣 \(a_i\)​ 名士兵去争夺这个城堡,使得总士兵数不超过 \(m\)

如果一名玩家向第 \(i\) 座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得 \(i\) 分。

现在小 C 即将和其他 \(s\) 名玩家两两对战,这 \(s\) 场对决的派遣士兵方案必须相同。小 C 通过某些途径得知了其他 \(s\) 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。

由于答案可能不唯一,你只需要输出小 C 总分的最大值

solution

我们先从部分分入手:

  1. \(s==1\)的时候

我们可以把他当成一个\(01\)背包,背包总体积为m,每个城堡为每一件物品,他的价值为 \(i\) 及他的编号,他的体积为 \(2*\) 派兵的人数加一(保证严格大于其他玩家派兵的人数)。这样跑一遍\(01\)背包不就完事了吗 QAQ。。。。

这样你就会拿到 40-50pts。


附上 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;
}
原文地址:https://www.cnblogs.com/genshy/p/13347873.html