三分的多种写法及对应的精度 三分套三分原理

P.S.:

while

r-l>=minv1

f(r)-f(l)>=minv2 better!!!

=======================================

https://www.luogu.org/problemnew/show/P3382

正规三分法

study from:

https://blog.csdn.net/pi9nc/article/details/9666627

f '(x)递减

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <time.h>
 6 #include <string>
 7 #include <set>
 8 #include <map>
 9 #include <list>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <bitset>
14 #include <ext/rope>
15 #include <algorithm>
16 #include <iostream>
17 using namespace std;
18 #define ll long long
19 #define minv 1e-6
20 #define inf 1e9
21 #define pi 3.1415926536
22 #define E  2.7182818284
23 const ll mod=1e9+7;//998244353
24 const int maxn=1e2+10;
25 
26 int n;
27 double a[maxn];
28 
29 double f(double x)
30 {
31     double v=0;
32     int i;
33     for (i=n;i>=0;i--)
34         v=v*x+a[i];
35     return v;
36 }
37 
38 int main()
39 {
40     double l,r,m,mm;
41     int i;
42     scanf("%d%lf%lf",&n,&l,&r);
43     for (i=n;i>=0;i--)
44         scanf("%lf",&a[i]);
45     while (r-l>=minv)
46     {
47         m=(l+r)/2;
48         mm=(m+r)/2;
49         if (f(m)>f(mm))
50             r=mm;
51         else
52             l=m;
53     }
54     printf("%.5f",l);
55     return 0;
56 }

f '(x)递增

 1 if (f(m)>f(mm)) 2 l=m; 3 else 4 r=mm;

另外的写法

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <time.h>
 6 #include <string>
 7 #include <set>
 8 #include <map>
 9 #include <list>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <bitset>
14 #include <ext/rope>
15 #include <algorithm>
16 #include <iostream>
17 using namespace std;
18 #define ll long long
19 #define minv 1e-6
20 #define inf 1e9
21 #define pi 3.1415926536
22 #define E  2.7182818284
23 const ll mod=1e9+7;//998244353
24 const int maxn=1e2+10;
25 
26 int n;
27 double a[maxn];
28 
29 double f(double x)
30 {
31     double v=0;
32     int i;
33     for (i=n;i>=0;i--)
34         v=v*x+a[i];
35     return v;
36 }
37 
38 int main()
39 {
40     double l,r,m,mm;
41     int i;
42     scanf("%d%lf%lf",&n,&l,&r);
43     for (i=n;i>=0;i--)
44         scanf("%lf",&a[i]);
45     while (r-l>=minv)
46     {
47         m=(l+l+r)/3;
48         mm=(l+r+r)/3;
49         if (f(m)>f(mm))
50             r=mm;
51         else
52             l=m;
53     }
54     printf("%.5f",l);
55     return 0;
56 }

r-l缩减为原来的

way1

3/4

1/2

way2

1/3

1/3

平均

1/4(1-3/4)+1/2(1-1/2)>1/3+1/3

最差

1/3<1/2

不太确定它们的精度是否有区别,网上也找不到类似的文章,个人倾向于区别不大。

不同数据规模缩小的比较

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 using namespace std;
 9 #define ll long long
10 
11 const double eps=1e-8;
12 const ll inf=1e9;
13 const ll mod=1e9+7;
14 const int maxn=1e5+10;
15 
16 
17 
18 int main()
19 {
20     int i;
21     double j1=1,j2=1,j3=1,k1,k2,k3;
22     k1=4.0/3;
23     k2=3.0/2;
24     k3=2;
25     for (i=1;i<=50;i++)
26         j1=j1*k1,j2=j2*k2,j3=j3*k3;
27     printf("%.5f
%.5f
%.5f",j1,j2,j3);
28     return 0;
29 }
30 /*
31 10
32 17.75773
33 57.66504
34 1024.00000
35 
36 50
37 1765780.96326
38 637621500.21405
39 1125899906842624.00000
40 
41 100
42 3117982410207.92578
43 406561177535215232.00000
44 1267650600228229401496703205376.00000
45 */

=========================================

强烈不建议使用之后的方法,因为精度不够,

同时,它们也能启发思路。

某一位置的上升/下降情况

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <time.h>
 6 #include <string>
 7 #include <set>
 8 #include <map>
 9 #include <list>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <bitset>
14 #include <ext/rope>
15 #include <algorithm>
16 #include <iostream>
17 using namespace std;
18 #define ll long long
19 #define minv 1e-8
20 #define inf 1e9
21 #define pi 3.1415926536
22 #define E  2.7182818284
23 const ll mod=1e9+7;//998244353
24 const int maxn=1e2+10;
25 
26 int n;
27 double a[maxn]; //不能用int
28 
29 double f(double x)
30 {
31     double v=0;
32     int i;
33     for (i=n;i>=0;i--)
34         v=v*x+a[i];
35     return v;
36 }
37 
38 int main()
39 {
40     int i;
41     double l,r,m;
42     cin>>n>>l>>r;
43     ///用lf读入,用f输出
44     for (i=n;i>=0;i--)
45         scanf("%lf",&a[i]);
46 //        cin>>a[i];
47     while (r-l>=minv)
48     {
49         m=(l+r)/2;
50         if (f(m-minv)<f(m+minv))
51             l=m;
52         else
53             r=m;
54     }
55     printf("%.5f",l);
56     return 0;
57 }

求导 递减 + -> -

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <time.h>
 6 #include <string>
 7 #include <set>
 8 #include <map>
 9 #include <list>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <bitset>
14 #include <ext/rope>
15 #include <algorithm>
16 #include <iostream>
17 using namespace std;
18 #define ll long long
19 #define minv 1e-6
20 #define inf 1e9
21 #define pi 3.1415926536
22 #define E  2.7182818284
23 const ll mod=1e9+7;//998244353
24 const int maxn=1e2+10;
25 
26 //Çóµ¼ º¯Êý + -> -
27 
28 int n;
29 double a[maxn];
30 
31 double f(double x)
32 {
33     double v=0;
34     for (int i=n;i>=1;i--)
35         v=v*x+a[i];
36     return v;
37 }
38 
39 int main()
40 {
41     int i;
42     double l,r,m;
43     cin>>n>>l>>r;
44     for (i=n;i>=0;i--)
45     {
46         cin>>a[i];
47         a[i]*=i;
48     }
49     while (r-l>minv)
50     {
51         m=(l+r)/2;
52         if (f(m)>0)
53             l=m;
54         else
55             r=m;
56     }
57     printf("%.5f",l);
58     return 0;
59 }

==================================

三分套三分...的原理:

f(x1,x2,...,xn)的最小值

x1,x2,..,xn分别为系数

前提:

任意一维下,f''(xk)>0 [其它系数的值为任意值]

证明:

对于一组数值(a1,a2,...,an)

对于任意的a2,...,an,根据f‘’(x1)>0,a1变为a1',其它系数不变,数值都是增加(减少/不变)了,这取决于f''(x1)下f(a1)和f(a1')的值。

f''(x1)下f(a1)和f(a1')的关系,与x1=a1,x1=a2时,函数取得最小值的数值的关系 是一致的。

在x1,...,xn-2系数确定时,

在不同的xn-1系数中,求出了xn系数下的最小值,从而决定了在x1,...,xn-2系数下,xn-1系数为某个值时是最小的。

在x1,...,xn-3系数确定时,

在不同的xn-2系数中,求出了xn-1系数下(已经知道了x1,...,xn-1系数的值,唯一决定xn系数的值)的最小值,从而决定了在x1,...,xn-3系数下,xn-2,xn-1系数为某个值时是最小的。

……

[大概那个意思,不好描述]

而单独求每个系数的最优值(而其它系数任意选值)不可行,原因是不同的函数下(常数为0的项的数值发生变化),最优点的位置不同。

题目:

三分套三分套三分

https://www.cnblogs.com/cmyg/p/9976329.html E题

三分套三分

http://acm.hdu.edu.cn/showproblem.php?pid=3400

Sol:https://blog.csdn.net/u011787119/article/details/44598871

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <time.h>
 6 #include <string>
 7 #include <set>
 8 #include <map>
 9 #include <list>
10 #include <stack>
11 #include <queue>
12 #include <vector>
13 #include <bitset>
14 #include <ext/rope>
15 #include <algorithm>
16 #include <iostream>
17 using namespace std;
18 #define ll long long
19 #define minv 1e-6
20 #define inf 1e9
21 #define pi 3.1415926536
22 #define E  2.7182818284
23 const ll mod=1e9+7;//998244353
24 const int maxn=1e5+10;
25 
26 double a,b,c,d,x,y,s,t;
27 double p,q,v;
28 double da,db,dx,dy;
29 double l,r,L,R;
30 double m,mm,M,MM;
31 
32 double F(double aa,double bb,double xx,double yy)
33 {
34     return sqrt(pow(aa-a,2)+pow(bb-b,2))/p+
35         sqrt(pow(s-xx,2)+pow(t-yy,2))/q+
36         sqrt(pow(aa-xx,2)+pow(bb-yy,2))/v;
37 }
38 
39 double f(double aa,double bb)
40 {
41     L=0; R=1.0;
42     while (R-L>minv)
43     {
44         M=(L+R)/2;
45         MM=(M+R)/2;
46         if (F(aa,bb,s+dx*M,t+dy*M)>F(aa,bb,s+dx*MM,t+dy*MM))
47             L=M;
48         else
49             R=MM;
50     }
51     return F(aa,bb,s+dx*L,t+dy*L);
52 }
53 
54 int main()
55 {
56     int T;
57     scanf("%d",&T);
58     while (T--)
59     {
60         scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
61         scanf("%lf %lf %lf %lf",&x,&y,&s,&t);
62         scanf("%lf %lf %lf",&p,&q,&v);
63         da=c-a;
64         db=d-b;
65         dx=x-s;
66         dy=y-t;
67         l=0; r=1.0;
68         while (r-l>minv)
69         {
70             m=(l+r)/2;
71             mm=(m+r)/2;
72             if (f(a+da*m,b+db*m)>f(a+da*mm,b+db*mm))
73                 l=m;
74             else
75                 r=mm;
76         }
77         printf("%.2f
",F(a+da*m,b+db*m,s+dx*M,t+dy*M));
78     }
79     return 0;
80 }

实验证明单独求每个系数的最优值(而其它系数任意选值)不可行

错误代码

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <time.h>
  6 #include <string>
  7 #include <set>
  8 #include <map>
  9 #include <list>
 10 #include <stack>
 11 #include <queue>
 12 #include <vector>
 13 #include <bitset>
 14 #include <ext/rope>
 15 #include <algorithm>
 16 #include <iostream>
 17 using namespace std;
 18 #define ll long long
 19 #define minv 1e-6
 20 #define inf 1e9
 21 #define pi 3.1415926536
 22 #define E  2.7182818284
 23 const ll mod=1e9+7;//998244353
 24 const int maxn=1e5+10;
 25 
 26 double a,b,c,d,x,y,s,t;
 27 double p,q,v;
 28 double da,db,dx,dy;
 29 double l,r,L,R;
 30 double m,mm,M,MM;
 31 
 32 double F(double aa,double bb,double xx,double yy)
 33 {
 34     return sqrt(pow(aa-a,2)+pow(bb-b,2))/p+
 35         sqrt(pow(s-xx,2)+pow(t-yy,2))/q+
 36         sqrt(pow(aa-xx,2)+pow(bb-yy,2))/v;
 37 }
 38 
 39 int main()
 40 {
 41     double r1,r2;
 42     int T;
 43     scanf("%d",&T);
 44     while (T--)
 45     {
 46         scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
 47         scanf("%lf %lf %lf %lf",&x,&y,&s,&t);
 48         scanf("%lf %lf %lf",&p,&q,&v);
 49         da=c-a;
 50         db=d-b;
 51         dx=s-x;
 52         dy=t-y;
 53 
 54         l=0; r=1.0;
 55         while (r-l>1e-15)///da,db*minv<...
 56         {
 57             m=(l+r)/2;
 58             mm=(m+r)/2;
 59             if (F(a+da*m,b+db*m,x,y)>F(a+da*mm,b+db*mm,x,y))
 60                 l=m;
 61             else
 62                 r=mm;
 63         }
 64         r1=m;
 65 
 66         l=0; r=1.0;
 67         while (r-l>1e-15)///dx,dy*minv<...
 68         {
 69             m=(l+r)/2;
 70             mm=(m+r)/2;
 71             if (F(a+da*r1,b+db*r1,x+dx*m,y+dy*m)>F(a+da*r1,b+db*r1,x+dx*mm,y+dy*mm))
 72                 l=m;
 73             else
 74                 r=mm;
 75         }
 76         r2=m;
 77 
 78 //        printf("%.5f %.5f
",r1,r2);
 79         printf("%.2f
",F(a+da*r1,b+db*r1,x+dx*r2,y+dy*r2));
 80     }
 81     return 0;
 82 }
 83 /*
 84 1
 85 0 1 2 3
 86 4 5 6 7
 87 100
 88 
 89 0 0 0 100
 90 100 0 100 100
 91 2 2 1
 92 
 93 0 1 2 3
 94 4 5 6 7
 95 10 5 3
 96 
 97 0 0 10 0
 98 20 0 20 20
 99 2 3 2
100 0.26668 0.77516
101 */

正确代码

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <time.h>
  6 #include <string>
  7 #include <set>
  8 #include <map>
  9 #include <list>
 10 #include <stack>
 11 #include <queue>
 12 #include <vector>
 13 #include <bitset>
 14 #include <ext/rope>
 15 #include <algorithm>
 16 #include <iostream>
 17 using namespace std;
 18 #define ll long long
 19 #define minv 1e-6
 20 #define inf 1e9
 21 #define pi 3.1415926536
 22 #define E  2.7182818284
 23 const ll mod=1e9+7;//998244353
 24 const int maxn=1e5+10;
 25 
 26 double a,b,c,d,x,y,s,t;
 27 double p,q,v;
 28 double da,db,dx,dy;
 29 double l,r,L,R;
 30 double m,mm,M,MM;
 31 
 32 double F(double aa,double bb,double xx,double yy)
 33 {
 34     return sqrt(pow(aa-a,2)+pow(bb-b,2))/p+
 35         sqrt(pow(s-xx,2)+pow(t-yy,2))/q+
 36         sqrt(pow(aa-xx,2)+pow(bb-yy,2))/v;
 37 }
 38 
 39 double f(double aa,double bb)
 40 {
 41     L=0; R=1.0;
 42     while (R-L>minv)
 43     {
 44         M=(L+R)/2;
 45         MM=(M+R)/2;
 46         if (F(aa,bb,s+dx*M,t+dy*M)>F(aa,bb,s+dx*MM,t+dy*MM))
 47             L=M;
 48         else
 49             R=MM;
 50     }
 51     return F(aa,bb,s+dx*L,t+dy*L);
 52 }
 53 
 54 int main()
 55 {
 56     int T;
 57     scanf("%d",&T);
 58     while (T--)
 59     {
 60         scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
 61         scanf("%lf %lf %lf %lf",&x,&y,&s,&t);
 62         scanf("%lf %lf %lf",&p,&q,&v);
 63         da=c-a;
 64         db=d-b;
 65         dx=x-s;
 66         dy=y-t;
 67         l=0; r=1.0;
 68         while (r-l>minv)
 69         {
 70             m=(l+r)/2;
 71             mm=(m+r)/2;
 72             if (f(a+da*m,b+db*m)>f(a+da*mm,b+db*mm))
 73                 l=m;
 74             else
 75                 r=mm;
 76         }
 77         printf("%.5f %.5f
",m,M);
 78         printf("%.2f
",F(a+da*m,b+db*m,s+dx*M,t+dy*M));
 79     }
 80     return 0;
 81 }
 82 /*
 83 100
 84 
 85 0 0 0 100
 86 100 0 100 100
 87 2 2 1
 88 
 89 0 1 2 3
 90 4 5 6 7
 91 10 5 3
 92 
 93 0 0 10 0
 94 20 0 20 20
 95 2 3 2
 96 0.00000 0.10557
 97 
 98 0 0 10 0
 99 20 0 20 20
100 5 5 3
101 1.00000 0.62500
102 */

http://acm.hdu.edu.cn/showproblem.php?pid=4717

Sol:https://www.cnblogs.com/crazyapple/p/3315633.html

多个二次函数的最大值是三分函数的证明

https://www.cnblogs.com/cmyg/p/9784683.html

原文地址:https://www.cnblogs.com/cmyg/p/9554220.html