• 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;
    }
    
  • 相关阅读:
    小程序方法-小程序获取上一页的数据修改上一个页面的数据
    小程序方法-上传多上图片
    小程序方法-时间转换年月日,时间转换几天前几个小时前刚刚
    opencv函数学习:LUT()的使用
    opencv函数学习:cvtColor()的使用
    opencv函数学习:convertTo()的使用
    BITMAPFILEHEADER、BITMAPINFOHEADER及BMP结构详解
    单通道图和三通道图
    计算机存储单位与宽带单位
    大端模式和小端模式
  • 原文地址:https://www.cnblogs.com/genshy/p/13347873.html
Copyright © 2020-2023  润新知