新賽道-2024.8 CSP-J組月賽-T4

谦谦2022發表於2024-09-01

題目描述

王老師 最近搬家了,需要購置 a 臺家電、b 件傢俱和 c 個裝飾。他來到了商場,商場正好在舉行優惠大酬賓,每家店鋪都推出了一系列活動。

一共有 n=a+b+c 家店鋪,活動期間在第 i 家店鋪購買家電只需要 ai 元一臺,購買傢俱只需要 bi 元一件,購買裝飾只需要 ci 元一個,但每一家店鋪限定每位顧客最多隻能購買一種型別的物品一個。

王老師 希望在滿足採購需求的情況下總花費最少,你能幫幫他求出最小花費嗎?

資料範圍

對於所有資料 n,a,b,c5000,ai,bi,ci109 ,保證 n=a+b+c 。

測試點資料範圍
14 n15
510 n100
1114 c=0
1520 無限制

首先根據題面不難想到定義dp[i][j][k](表示經過i家店鋪,買j臺家電,k件傢俱,n-j-k個裝飾的最小花費),但只能過%50分。

考慮最佳化:我們可以利用貪心來最佳化dp[i][j]表示考慮了1到i家店,選了j個裝飾的最小費用,那麼剩下i-j個物品就會按照貪心策略優先買購買傢俱,然後購買家電。

按b[i]-a[i]排序,便有以下轉移方程

若i-j<=B f[i][j]=min(f[i-1][j-1]+c[i],f[i-1][j]+b[i])

否則:f[i][j]=min(f[i-1][j-1]+c[i],f[i-1][j]+a[i]);

程式碼:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int f[5005][5005],n,a,b,c;
struct node{
int a,b,c;
}s[5005];
bool cmp(node x,node y){
return x.b-x.a<y.b-y.a;
}
signed main(){
freopen("buy.in","r",stdin);
freopen("buy.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>a>>b>>c;
for(int i=1;i<=n;i++)cin>>s[i].a>>s[i].b>>s[i].c;
sort(s+1,s+n+1,cmp);
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=min(i,c);j++){
if(i-j<=b)f[i][j]=f[i-1][j]+s[i].b;
else f[i][j]=f[i-1][j]+s[i].a;
if(j!=0)f[i][j]=min(f[i][j],f[i-1][j-1]+s[i].c);
}
cout<<f[n][c];
return 0;
}
總結:T4在考場上寫了個記憶化搜尋,但是狀態寫錯了,以至於與爆搜的20分都沒拿到。。而且即便大樣例過了,也有可能爆0,所以不能過度依賴大樣例,需要自己造hack資料。

相關文章