1. 程式人生 > >zoj3956(Course Selection System)_Solution

zoj3956(Course Selection System)_Solution

-- std system turn void div lib rst iou

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

技術分享

zoj3956(Course Selection System)_Solution