码迷,mamicode.com
首页 > 其他好文 > 详细

【Foreign】咏叹 [模拟退火]

时间:2017-04-09 00:23:07      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:show   enter   void   alt   time   最大   tput   最优   长度   

咏叹

Time Limit: 100 Sec  Memory Limit: 256 MB

Description

  有n根木棍,第i根长度为ai。你要贴着墙围出一个矩形区域,木棍围成的矩形边缘必须平行或垂直于墙,且又一边必须利用墙。你可以把至多1根木棍劈成两根(不一定要在整数位置)。最大化矩形面积。

Input

  包含多组数据。每组数据第一行一个整数n,第二行n个整数ai。

Output

  输出面积最大的矩形与墙壁平行的那条边的长度(显然是一个整数),若有多个最优解输出与墙壁平行的那条边最长的。

Sample Input

    3
    3 3 3
    4
    4 4 4 4

Sample Output

  6
  8

HINT

  对于10%的数据,n=2。
  对于30%的数据,n<=15。
  对于50%的数据,n<=32。
  对于另外20%的数据,ai<=100。
  对于100%的数据,2<=n<=40,1<=ai<=10^9,数据不超过10组。

Source

  首先,必然是全部木棍都用上的时候最优,对于n=2的时候,显然就是分三种情况讨论一下就好了。

  然后我们从n=2的情况拓展。发现,其实可以把多个木棍并在一起,使其变为n=2的情况,然后讨论。那么现在答案只和两段的长度有关了。

  但是直接暴力搜索是O(2^40)的,显然不行,我们考虑分为两部分来搜索,搜索前n/2个,和后n/2个,表示选不选得到的价值,现在效率是O(2*2^20)。

  然后怎么得到答案呢?显然:如果我们设宽为x,则长为tot-2x(tot为总长),那么这是一个二次函数,必然有峰值。

  所以我们大胆猜测,我们确定了一半,另外一半使得其答案最优的话也可能满足有峰值的性质

  然后我们固定一半,另一半运用模拟退火求解即可!

Code

技术分享
  1 #include<iostream>  
  2 #include<string>  
  3 #include<algorithm>  
  4 #include<cstdio>  
  5 #include<cstring>  
  6 #include<cstdlib>  
  7 #include<cmath>
  8 #include<ctime>
  9 using namespace std; 
 10 typedef long long s64;
 11 
 12 const int ONE = 2100000;
 13 
 14 int T,n;
 15 int a[45],top1,top2;
 16 s64 Stk1[ONE],Stk2[ONE];
 17 s64 Square, Ans, tot, RE;
 18 
 19 int get() 
 20 {
 21         int res=1,Q=1;  char c;
 22         while( (c=getchar())<48 || c>57)
 23         if(c==-)Q=-1;
 24         if(Q) res=c-48; 
 25         while((c=getchar())>=48 && c<=57) 
 26         res=res*10+c-48; 
 27         return res*Q; 
 28 }
 29 
 30 s64 Get(s64 width,s64 length)
 31 {
 32         s64 res = length * width;
 33         
 34         if(res > Square || (res==Square && length>Ans))
 35             Square = res, Ans = length;
 36         return res;
 37 }
 38 
 39 s64 Check(s64 A,s64 B)
 40 {
 41         if(A > B) swap(A,B);
 42         s64 res = 0;
 43         res = max(res,Get(A, B-A));
 44         res = max(res,Get(A/2,B));
 45         res = max(res,Get(B/2,A));
 46         return res;
 47 }
 48 
 49 void Dfs1(s64 val,int T)
 50 {
 51         if(T>n/2) {Stk1[++top1] = val; return;}
 52         Dfs1(val,T+1);    Dfs1(val+a[T],T+1);
 53 }
 54 
 55 void Dfs2(s64 val,int T)
 56 {
 57         if(T>n) {Stk2[++top2] = val; return;}
 58         Dfs2(val,T+1);    Dfs2(val+a[T],T+1);
 59 }
 60 
 61 s64 Judge(int i,int j)
 62 {
 63         return Check(Stk1[j] + Stk2[i],tot - Stk1[j] -Stk2[i]);
 64 }
 65 
 66 double Random() {return (double)rand()/RAND_MAX;}
 67 void Deal(int id)
 68 {
 69         int Now = top2/2;
 70         double Temper = top2/3;
 71         while(Temper >= 1)
 72         {
 73             int A = Now + (int)Temper * (Random()*2.0-1);
 74             if(A<=0) A = (int)Temper * Random() + 1;
 75             s64 dE = Judge(A,id) - Judge(Now,id);
 76             if(dE > 0 || Random()<=exp(dE)) 
 77                 Now = A;
 78             if(Temper > top2 / 2) Temper *= 0.1;
 79             Temper *= 0.75;
 80         }
 81         Judge(Now-1,id);    Judge(Now+1,id);
 82 }
 83 
 84 void Solve2()
 85 {
 86         top1 = top2 = tot = 0;
 87         for(int i=1;i<=n;i++) a[i]=get(),a[i]*=2,tot += a[i]; 
 88         Dfs1(0,1);        sort(Stk1+1,Stk1+top1+1);    top1 = unique(Stk1+1,Stk1+top1+1)-Stk1-1;
 89         Dfs2(0,n/2+1);    sort(Stk2+1,Stk2+top2+1);    top2 = unique(Stk2+1,Stk2+top2+1)-Stk2-1;
 90         Ans = Square = 0;
 91         
 92         for(int i=1;i<=top1;i++)
 93             Deal(i);
 94         
 95         
 96         printf("%lld\n",Ans/2);
 97 }
 98 
 99 void Dfs(s64 A,s64 B,int T)
100 {
101         if(T>n)
102         {
103             Check(A,B);
104             return;
105         }
106         Dfs(A+a[T],B,T+1);
107         Dfs(A,B+a[T],T+1);
108 }
109 
110 void Solve1()
111 {
112         Ans = Square = 0;
113         for(int i=1;i<=n;i++) a[i]=get(),a[i]*=2;
114         Dfs(0,0,1);
115         printf("%lld\n",Ans/2);
116 }
117 
118 int main()
119 {
120         srand(time(0));
121         while(scanf("%d",&n)!=EOF)
122         {
123             if(n <= 25) Solve1();
124             else Solve2(); 
125         }
126 }
View Code

 

【Foreign】咏叹 [模拟退火]

标签:show   enter   void   alt   time   最大   tput   最优   长度   

原文地址:http://www.cnblogs.com/BearChild/p/6683327.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!