zoj3956_Solution
H=sum(hi),C=sum(ci),Value=H*H-H*C-C*C
求Value的最大值
Solution:
动态规划:
共两维:H,C 固定一维C,在该维值C相同的情况下另一维应最大H,从而动态规划另一维H,转变为01背包问题。
优化:
H*H-H*C-C*C=0 (H,C>0)
H/C=(1+sqrt(5))/2=1.6180…
必会选择h/c>(1+sqrt(5))/2 的(h,c)对
证明:
若Value大于0,则H/C>(1+sqrt(5))/2,
若再加上h/c>(1+sqrt(5))/2 的(h,c)对,
(H+h)* (H+h)-(H+h) *(C+c)-(C+c)* (C+c)=H*H-H*C-C*C+h*h-h*c-c*c+2*H*h-H*c-h*C-2*C*c
[ (H+h)* (H+h)-(H+h) *(C+c)-(C+c)* (C+c) ] – [ H*H-H*C-C*C ]
= h*h-h*c-c*c+2*H*h-H*c-h*C-2*C*c
>2*H*h-H*c-h*C-2*C*c
>2*H*h - H*h*(1+sqrt(5))/2 - h*H*(1+sqrt(5))/2 – 2*H*(1+sqrt(5))/2*h*(1+sqrt(5))/2
=0
值必然会增大,所以必会选择h/c>(1+sqrt(5))/2 的(h,c)对,得证
所以可以把h/c>=(1+sqrt(5))/2的(h,c)对先选出来,再对h/c<(1+sqrt(5))/2的(h,c)对进行动态规划,然后在动态规划的基础上再加上h/c>=(1+sqrt(5))/2的(h,c)对求得在相同C的基础上H的最大值。
某个贪心的方法:按照h/c从大到小的顺序依次对h,c对进行排序,然后依次选取,直到值小于0。
证明不成立:
原来 H,C value
加入 h1,c1 value1
再加入 h2,c2 value2
(h1/c1>h2/c2)
若原来加入 h2,c2 value3
证明有可能只加入h2,c2数值更大:
h1,c1数值非常大,且h1/c1<(1+sqrt(5))/2,加入h1,c1后value1<0,而再加入h2,c2后,value2<value1<0;而尽管h2/c2< h1/c1<(1+sqrt(5))/2,但加入h2,h2后,value2>value。
如H=1700,C=1000
h1=16000,c1=10000
h2=159,c1=100
value=190000
value1=-2410000
value2=-2501019
value3=200981
当有三个数据(1700,1000),(16000,10000),(159,100),则用此方法求得结果为190000,并不正确。所以该方法错误。
DP:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define maxn 500 4 5 int main() 6 { 7 //500*100(total) *500(n) *10(test cases)=250000000 8 9 //max_result=(10000*500)^2 10 //the maximum of h[i] is larger than c[i],thus choose c 11 //the total of c is not larger than 500*100=50000 12 //when c is the same , we need maximum h 13 long h[maxn+1],c[maxn+1]; 14 //<=10000/100*500 15 long t,n,i,j,k,ans[maxn+1],f[50001]; 16 long long s,result; 17 scanf("%ld",&t); 18 for (k=1;k<=t;k++) 19 { 20 ans[0]=0; 21 result=0; 22 scanf("%ld",&n); 23 for (i=1;i<=n;i++) 24 { 25 scanf("%ld %ld",&h[i],&c[i]); 26 ans[i]=ans[i-1]+c[i]; 27 } 28 for (i=1;i<=ans[n];i++) 29 f[i]=-1; 30 f[0]=0; 31 for (i=1;i<=n;i++) 32 //when choose course ith ,the maximum of credit is ans[i](including c[i]) 33 for (j=ans[i];j>=c[i];j--) 34 if (f[j-c[i]]!=-1 && f[j-c[i]]+h[i]>f[j]) 35 f[j]=f[j-c[i]]+h[i]; 36 for (i=1;i<=ans[n];i++) 37 if (f[i]!=-1) 38 { 39 s=f[i]*f[i]-f[i]*i-i*i; 40 if (s>result) 41 result=s; 42 } 43 printf("%lld\n",result); 44 } 45 return 0; 46 } 47 /* 48 100 1 1 1 1 1 1 1 1 49 0+101+102+…… 50 not obvious 51 52 WorstSituation 53 10 10 10 10 10 54 50+50+50+50+50=250 55 0+10+20+30+40=100 56 save halt of the time 57 58 Previous: 59 49900*500=24950000 60 Current: 61 0+100+200+…+49900=12500000 62 10Cases 63 12500000*10=1,2500,0000 64 */
DP(advance):
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define maxn 500 4 5 //原来60s,现在20s 6 7 int main() 8 { 9 //500*100(total) *500(n) *10(test cases)=250000000 10 11 //max_result=(10000*500)^2 12 //the maximum of h[i] is larger than c[i],thus choose c 13 //the total of c is not larger than 500*100=50000 14 //when c is the same , we need maximum h 15 long h[maxn+1],c[maxn+1],ans[maxn+1],f[50001]; 16 //<=10000/100*500 17 long t,n,i,j,k,g,temp,hh,cc; 18 long long s,result; 19 double line=(1.0+sqrt(5.0))/2; 20 scanf("%ld",&t); 21 for (k=1;k<=t;k++) 22 { 23 ans[0]=0; 24 scanf("%ld",&n); 25 for (i=1;i<=n;i++) 26 scanf("%ld %ld",&h[i],&c[i]); 27 g=n+1; 28 for (i=n;i>=1;i--) 29 if (1.0*h[i]/c[i]>=line) 30 { 31 g--; 32 temp=h[i]; 33 h[i]=h[g]; 34 h[g]=temp; 35 temp=c[i]; 36 c[i]=c[g]; 37 c[g]=temp; 38 } 39 g--; 40 //a[g+1]~a[n] h[i]/c[i]>=line must be chose 41 hh=0; 42 cc=0; 43 for (i=g+1;i<=n;i++) 44 { 45 hh+=h[i]; 46 cc+=c[i]; 47 } 48 //a[1]~a[g] h[i]/c[i]<line 49 for (i=1;i<=g;i++) 50 ans[i]=ans[i-1]+c[i]; 51 for (i=1;i<=ans[g];i++) 52 f[i]=-1; 53 f[0]=0; 54 for (i=1;i<=g;i++) 55 //when choose course ith ,the maximum of credit is ans[i](including c[i]) 56 for (j=ans[i];j>=c[i];j--) 57 if (f[j-c[i]]!=-1 && f[j-c[i]]+h[i]>f[j]) 58 f[j]=f[j-c[i]]+h[i]; 59 result=hh*hh-hh*cc-cc*cc; 60 for (i=1;i<=ans[g];i++) 61 if (f[i]!=-1) 62 { 63 s=(f[i]+hh)*(f[i]+hh)-(f[i]+hh)*(i+cc)-(i+cc)*(i+cc); 64 if (s>result) 65 result=s; 66 } 67 printf("%lld\n",result); 68 } 69 return 0; 70 } 71 /* 72 100 1 1 1 1 1 1 1 1 73 0+101+102+…… 74 not obvious 75 76 WorstSituation 77 10 10 10 10 10 78 50+50+50+50+50=250 79 0+10+20+30+40=100 80 save halt of the time 81 82 Previous: 83 49900*500=24950000 84 Current: 85 0+100+200+…+49900=12500000 86 10Cases 87 12500000*10=1,2500,0000 88 */
贪心(Wrong):
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define maxn 500 4 5 struct node 6 { 7 long h,c; 8 double per; 9 }; 10 11 int cmp(const void *a,const void *b) 12 { 13 if ((*(struct node *)b).per>(*(struct node *)a).per) 14 return 1; 15 else 16 return 0; 17 } 18 19 long long max(long long a,long long b) 20 { 21 if (a>b) 22 return a; 23 else 24 return b; 25 } 26 27 int main() 28 { 29 long t,k,l,n,ht,ct; 30 long long maxs; 31 struct node course[maxn+1]; 32 scanf("%ld",&t); 33 for (k=1;k<=t;k++) 34 { 35 scanf("%ld",&n); 36 for (l=0;l<n;l++) 37 { 38 scanf("%ld%ld",&course[l].h,&course[l].c); 39 course[l].per=1.0*course[l].h/course[l].c; 40 } 41 qsort(course,n,sizeof(struct node),cmp); 42 ht=0; 43 ct=0; 44 maxs=0; 45 for (l=0;l<n;l++) 46 { 47 ht+=course[l].h; 48 ct+=course[l].c; 49 maxs=max(maxs,ht*ht-ht*ct-ct*ct); 50 } 51 printf("%lld\n",maxs); 52 } 53 return 0; 54 } 55 /* 56 5 57 1 4 58 2 5 59 6 3 60 7 2 61 4 4 62 */
最普通的方法,保证正确,用于测试其它程序是否正确:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct node 5 { 6 long h,c; 7 double per; 8 }; 9 long n; 10 long long maxs=0; 11 struct node course[501]; 12 13 int cmp(const void *a,const void *b) 14 { 15 return (*(struct node *)b).per-(*(struct node *)a).per; 16 } 17 18 long long max(long long a,long long b) 19 { 20 if (a>b) 21 return a; 22 else 23 return b; 24 } 25 26 void dfs(long d,long ht,long ct) 27 { 28 if (d==n) 29 return ; 30 if (ct!=0) 31 maxs=max(maxs,ht*ht-ht*ct-ct*ct); 32 dfs(d+1,ht+course[d].h,ct+course[d].c); 33 dfs(d+1,ht,ct); 34 } 35 36 int main() 37 { 38 long t,k,l; 39 scanf("%ld",&t); 40 for (k=1;k<=t;k++) 41 { 42 scanf("%ld",&n); 43 maxs=0; 44 for (l=0;l<n;l++) 45 { 46 scanf("%ld%ld",&course[l].h,&course[l].c); 47 course[l].per=1.0*course[l].h/course[l].c; 48 } 49 dfs(0,0,0); 50 printf("%lld\n",maxs); 51 } 52 return 0; 53 }
以下是我做的关于此题做的评测方法,值得一览
http://pan.baidu.com/s/1c1WeUGS