[bzoj1038] [ZJOI2008]瞭望塔

  看到半平面交吓傻了。

  Po姐教你模拟退火乱搞233

  模拟退火横坐标,然后塔的高度二分一下就行了。

  然而交上去一直tle= =。。。。把模拟退火那部分改得和标程一模一样还是跪。。

  最后真相是二分的时候double精度会炸(掀桌。。。然而标程不知为啥用double活得好好的(虽然随便随机一个数据就能卡。。

  改成long double就过了= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #define d double
 7 #define ld long double
 8 using namespace std;
 9 const int maxn=323;
10 const d eps=1e-7;
11 struct poi{
12     int x,y;
13 }a[maxn];
14 d ansx,ansaddy,nowx,nowy;int posl,posr;
15 int i,j,k,n,m;
16 
17 int ra,fh;char rx;
18 inline int read(){
19     rx=getchar(),ra=0,fh=1;
20     while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();
21     if(rx=='-')fh=-1,rx=getchar();
22     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh;
23 }
24 
25 inline d randlf(){
26     return rand()%10000/10000.0;
27 }
28 bool judge(){
29     int i;
30     for(i=1;i<posl;i++)if((nowy-a[i].y)*(nowx-a[i+1].x)>(nowy-a[i+1].y)*(nowx-a[i].x))
31         return 0;
32     for(i=posr;i<n;i++)if((a[i].y-nowy)*(a[i+1].x-nowx)>(a[i+1].y-nowy)*(a[i].x-nowx))
33         return 0;
34     return 1;
35 }
36 inline d geth(){
37     int L=1,R=n,MID;ld sy,l,r,mid;
38     while(L<R)
39         if(a[(MID=(L+R+1)>>1)].x<=nowx)L=MID;else R=MID-1;
40     posl=L,posr=L+1;
41     if(a[L].x==nowx)posl--,sy=a[L].y;else sy=a[posl].y+(a[posr].y-a[posl].y)*(nowx-a[posl].x)/(a[posr].x-a[posl].x);
42     l=0,r=1e11;//printf("geth:  x:%.8lf   l r:%d %d   sy:%.3lf\n",nowx,a[posl].x,a[posr].x,sy);
43     while(l+1e-7<r){
44         mid=(l+r)/2;nowy=sy+mid;
45         if(judge())r=mid;//,printf("success:  %.2lf %.2lf   %.9lf\n",nowx,(d)sy,(d)mid);
46         else l=mid;//,printf("failed:  %.2lf %.2lf   %.9lf  %.9lf %.9lf\n",nowx,(d)sy,(d)mid,(d)l,(d)r);
47     }
48     if(l<ansaddy)ansaddy=l,ansx=nowx;
49     return l;
50 }//<n*64
51 inline void SA(){
52     d T=a[n].x-a[1].x,prex,tmpaddy,nowaddy;
53     nowx=ansx=(a[n].x+a[1].x)/2.0;nowaddy=geth();//printf("   %.2lf\n",nowx);
54     while(T>1e-5){
55         T*=0.99;//printf("!  %d\n",fabs(nowaddy-geth())<=eps);
56         prex=nowx,nowx+=T*(randlf()*2-1);
57     //    printf("try:%.3lf\n",nowx);
58         if(nowx<a[1].x||nowx>a[n].x){nowx=prex;T/=0.991;continue;}
59         tmpaddy=geth();
60         
61         if(tmpaddy>nowaddy&&exp((nowaddy-tmpaddy)/T)<randlf())
62             nowx=prex;
63         else nowaddy=tmpaddy;
64     }
65     for(int i=1;i<=1023;i++){
66         nowx=ansx+T*(randlf()*2-1);//printf("try1:%.3lf\n",nowx);
67         if(nowx<a[1].x||nowx>a[n].x)continue;
68         geth();
69     }
70 }
71 int main(){
72     n=read();srand(233);
73 //    srand(19980406);
74     for(i=1;i<=n;i++)a[i].x=read();
75     for(i=1;i<=n;i++)a[i].y=read();ansaddy=1e11;
76     SA();
77     printf("%.3lf\n",ansaddy+eps);//printf("ansx:  %.3lf\n",ansx);
78     return 0;
79 }
View Code

 

转载于:https://www.cnblogs.com/czllgzmzl/p/5301456.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (树形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用树形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵树,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 树形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值