• 【Foreign】咏叹 [模拟退火]


    咏叹

    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组。

    Solution

      首先,必然是全部木棍都用上的时候最优,对于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
    ",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
    ",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
  • 相关阅读:
    ArcObject获取ArcMap默认地理数据库的路径
    标准IO
    进程关系
    进程环境
    C语言基础知识位运算
    Bash 快捷键
    信号
    UNIX系统文件
    进程
    unix 文件属性
  • 原文地址:https://www.cnblogs.com/BearChild/p/6683327.html
Copyright © 2020-2023  润新知