• 2019银川icpc A 分组背包


    题意:

    n n n张卡片,每张卡片有 n a m e , c o l o r , p o w e r name,color,power name,color,power属性,给出 5 5 5个特殊的 n a m e name name 1 1 1个特殊的 c o l o r color color。总得分定义为卡片的 p o w e r power power之和乘 b o n u s bonus bonus系数,初始是 b o n u s bonus bonus 1 1 1,每张卡片满足 n a m e name name是特殊的时候 b o n u s + 0.1 bonus+0.1 bonus+0.1 c o l o r color color是特殊的时候 b o n u s + 0.2 bonus+0.2 bonus+0.2。需要从 n n n张卡内选出 5 5 5张,使得他们 n a m e name name两两互异,并且使得总得分最大

    Solution:

    明显是个分组背包,但如何定义状态?若我们像普通的分组背包,定义 f [ i ] f[i] f[i]为已装 i i i容量的物品的最大价值,实际上题目的价值是随前面的总价值变化而变化的,难以转移,并且似乎考虑不到所有的状态。造成这一现象的原因是 b o n u s bonus bonus在变化,于是考虑将 b o n u s bonus bonus加入状态,定义 f [ i ] [ j ] f[i][j] f[i][j]为装了容量为 i i i的物品,此时 b o n u s = 10 × j bonus=10\times j bonus=10×j的最大 p o w e r power power和为多少,这样就能够考虑到所有状态了。显然我们首先需要对卡片按名字分组,于是不妨来一次排序,然后双指针找出同名的一段,枚举加入的卡片为 k k k,有
    d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − v a l ] + a [ k ] . p o w e r ) ; dp[i][j]=max(dp[i][j],dp[i-1][j-val]+a[k].power); dp[i][j]=max(dp[i][j],dp[i1][jval]+a[k].power);
    答案就是 m a x ( d p [ 5 ] [ i ] + d p [ 5 ] [ i ] ∗ i / 10 ) max(dp[5][i]+dp[5][i]*i/10) max(dp[5][i]+dp[5][i]i/10)。需要注意初始化时只有 d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0,其他都置为负无穷,以保证转移的源头都是状态 ( 0 , 0 ) (0,0) (0,0)

    #ifndef stdjudge
    #include
    #endif
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    using namespace std;
    
    using ll=long long;
    const int N=1e5+5,inf=0x3fffffff;
    const long long INF=0x3fffffffffffffff,mod=998244353;
    
    struct poker
    {
    	string name,color;
    	int power;
    	bool operator<(const poker& x) const {
    		return name<x.name;
    	}
    }a[N];
    unordered_map<string,bool>map1;
    string color;
    
    int n;
    ll dp[6][16];
    
    int getval(int x) {
    	return map1.count(a[x].name)+2*(a[x].color==color);
    }
    
    int main()
    {
    	#ifdef stdjudge
    		freopen("in.txt","r",stdin);
    	#endif
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	int t; cin>>t;
    	while(t--)
    	{
    		cin>>n; map1.clear();
    		for(int i=1;i<=n;i++) cin>>a[i].name>>a[i].color>>a[i].power;
    		for(int i=1;i<=5;i++)
    		{
    			cin>>color;
    			map1[color]=true;
    		} 
    		cin>>color;
    		sort(a+1,a+1+n);
    		for(int i=0;i<=5;i++)
    			for(int j=0;j<=15;j++) dp[i][j]=-INF;
    		int l=1,r=1; dp[0][0]=0;
    		while(l<=n)
    		{
    			while(r+1<=n&&a[r+1].name==a[l].name) r++;
    			for(int i=5;i>=1;i--)
    			{
    				for(int j=0;j<=15;j++)
    				{
    					for(int k=l;k<=r;k++)
    					{
    						int val=getval(k);
    						if(j>=val) dp[i][j]=max(dp[i][j],dp[i-1][j-val]+a[k].power);
    					}
    				}
    			}
    			l=++r;
    		}
    		ll ans=-INF;
    		for(int i=0;i<=15;i++) ans=max(ans,dp[5][i]+dp[5][i]*i/10);
    		cout<<ans<<'\n';
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    云原生网关哪家强:Sealos 网关血泪史
    [iOS开发]iOS中TabBar中间按钮凸起的实现
    ESP32-CAM初始篇:Arduino环境搭建-->实现局域网推流
    既要便捷、安全+智能,也要颜值,萤石发布北斗星人脸锁DL30F和极光人脸视频锁Y3000FV
    AIE多吡啶萘酰亚胺荧光树形分子/AIE喹啉腈(QM)染料衍生物QM-OH的研究制备
    如何在 JavaScript 中使用媒体查询
    JS 类总结
    Java-数字处理类
    使用maven框架搭建一个IDEA插件项目
    基于JavaWeb的网页版邮箱系统设计与实现
  • 原文地址:https://blog.csdn.net/stdforces/article/details/127931358