这题怎么说呢?对他是如何想到这种方式不是很理解
我只能挑着说一下我的一些理解:
首先来说一下为什么必须是全换的:
分为两种情况:
第一种情况是:更换的高电压的灯泡的价格更低,那这个没什么好说的,肯定得换,因为换一半的话,由于还可以继续换,继续省钱,所以必须得换
第二种情况是:更换的高电压的灯泡的价格高,这种情况下,如果换到中途不换了,那么成本绝对是增加的,因为在这种情况下的最低成本只能在全部换或者全部不换的时候得到。
所以,要想得到最低的成本,那么必须要不然全换,要不然就不换。
但是还有一个问题,能不能将一种低电压的灯泡换为多种高电压的灯泡呢?
这肯定是不行的啊,因为这两种高电压的价格是不一样的,最低的成本价绝对不可能在一种灯泡换多种的情况下取得。
那么结果就很清晰了,一种灯泡要么换,要么不换,而且只能换一种,将这些情况都枚举出来,挑一种成本最小的就OK。
怎么枚举呢?当然是使用dp,使用dp可以让前面枚举过的情况在后面要用的时候 不用再去枚举。
当然还有一种方式,枚举所有的种类的子集,然后将不在这个子集中的灯泡换成价格最低的在这个集合中的高电压灯泡,但是这道题的输入规模是1000,这肯定是不能用的。
所以只能用汝佳的方式:
这种方式我还没有完全理解,因为他是怎么想到这种方式的呢?
下面是AC代码:其中使用了struct的小于符号的重载
//要想清楚,同一种灯泡要不然就全换,要不然就不换,而且要换就只能换成一种,不能这个换一点,那个换一点 //最优解一定在这些情况中产生 //然后从低电压的开始,换成最便宜的高电压,因为这样,一定是在减小的 //然后枚举子集,将子集中没有的那些种类,都换成比他电压高的最便宜的灯泡,总时间复杂度为3^n //但是此题的输入规模是1000,绝对不能枚举子集 //还是得使用动态规划 //但是他这个规划的思路是怎么来的呢? #include<cstdio> #include<algorithm>
#include<cstring> using namespace std; const int maxn = 1000 + 10; struct cat { int V,K,C,L;//k是电源的花费,c是一个灯泡的花费 bool operator < (cat B) { if(V < B.V) return true; else return false; } }Cat[maxn]; int Sum[maxn]; int vis[maxn]; int d[maxn]; int dp(int T) { if(vis[T]) return d[T]; vis[T] = 1; d[T] = Sum[T] * Cat[T].C + Cat[T].K; for(int i = 1;i < T;i++) { d[T] = min(d[T],dp(i) + (Sum[T] - Sum[i]) * Cat[T].C + Cat[T].K); } return d[T]; } int main() { #ifdef local freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int T; while(scanf("%d",&T) == 1 && T) { memset(vis,0,sizeof(vis)); for(int i = 1;i <= T;i++) { scanf("%d%d%d%d",&Cat[i].V,&Cat[i].K,&Cat[i].C,&Cat[i].L); } sort(Cat + 1,Cat + 1 + T); int sum = 0; for(int i = 1;i <= T;i++) { sum = sum + Cat[i].L; Sum[i] = sum; } printf("%d\n",dp(T)); } return 0; }