二分/分治训练总结
二分已经比较熟悉了 一本通oj都刷通了 但是宏观分治还是有所疏漏
【1】一元三次方程求解(equ.cpp)
有形如:ax3+bx2+cx+d=0这样的一个一元三次方程。给出该方程
中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根
(根的范围在-100至100之间),且根与根之差的绝对值≥1。
要求由小到大依次在同一行输出这三个实根(根与根之间留有空
格),并精确到小数点后2位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f
(x2)<0,则在(x1,x2)之间一定有一个根。
输入:a,b,c,d 输出:三个实根(根与根之间留有空格)
【输入输出样例】
输入:1 -5 -4 20 输出:-2.00 2.00 5.00
这个比较简单 提示明显提示了可以用二分来做 这同样也是数学上找根的方法
只要三个根 那就每找出一个根就记一次数 并注意判重 sum == 3时结束
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #define int double 5 using namespace std; 6 int a,b,c,d; 7 int l = -100; 8 int r = 100; 9 int mid; 10 double fc(double x){ 11 return a * x * x * x + b * x * x + c * x + d; 12 }//写个函数方便用 13 int chk(int x){ 14 if(fc(l) * fc(x) < 0) return 1; 15 else return 0; 16 }//本题二分的精髓 17 signed sum = 0; 18 signed main(){ 19 freopen("equ.in","r",stdin); 20 freopen("equ.out","w",stdout); 21 cin>>a>>b>>c>>d; 22 for(register signed i = -100;i<=100;i++){ 23 if(sum == 3) return 0;//3个根结束程序 24 l = i; 25 r = l + 1; 26 if(fc(l) == 0) printf("%.2lf ",l),sum ++; 27 else if(chk(r) == 1) { 28 while (r - l >= 0.001) {//这里的0.001要注意 是为了控制double精度 29 mid = (l + r)/2; 30 if (chk(mid) == 1) 31 r = mid; 32 else 33 l = mid; 34 }printf("%.2lf ",r),sum ++;//每找出一个就记一次数 35 } 36 } 37 return 0; 38 }
【2】循环比赛日程表(match.cpp)
w 【问题描述】
w 设有N个选手进行循环比赛,其中N=2M,要求每名选手
要与其他N-1名选手都赛一次,每名选手每天比赛一次,循
环赛共进行N-1天,要求每天没有选手轮空。
w 输入:M
w 输出:表格形式的比赛安排表
w 【样例输入】match.in
w 3
w 【样例输出】match.out
w 1 2 3 4 5 6 7 8
w 2 1 4 3 6 5 8 7
w 3 4 1 2 7 8 5 6
w 4 3 2 1 8 7 6 5
w 5 6 7 8 1 2 3 4
w 6 5 8 7 2 1 4 3
w 7 8 5 6 3 4 1 2
w 8 7 6 5 4 3 2 1
这个题确实很好玩 仔细看样例就会发现 每个2^n * 2^n的矩阵都会在它的左下角/右下角被发现
例 :
1 2 3 4 5 6 7 8
2 1 4 3 6 5 8 7
3 4 1 2 7 8 5 6
4 3 2 1 8 7 6 5
5 6 7 8 1 2 3 4
6 5 8 7 2 1 4 3
7 8 5 6 3 4 1 2
8 7 6 5 4 3 2 1
这是2 * 2的矩阵 细看就会发现 这个规律同理于4 * 4 、8 * 8.。。。。。。。。
由此可得 只需每次完成一个小矩阵 进行左上右下的复制即可
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cmath> 5 #define int long long 6 using namespace std; 7 const int K = 1e4 +5; 8 int M; 9 int a[K][K]; 10 int mypow(int a,int b){ 11 int ret = 1; 12 while(b){ 13 if(b%2 == 1){ 14 ret *= a; 15 } 16 a = a*a; 17 b >>= 1; 18 19 } 20 return ret; 21 }//2^n的快速幂 防爆 22 void work(int k,int n){ 23 if(n < 1) return; 24 if(n == 2){ 25 a[k][1] = k; 26 a[k][2] = k+1; 27 a[k+1][1] = k+1; 28 a[k+1][2] = k; 29 }//构建矩阵 30 else{ 31 work(k,n/2); 32 work(k+n/2,n/2);//递归地处理每一次变换 33 for(register int i = k;i <= k + n/2 - 1;i++) for(register int j = n/2 + 1;j <= n;j++) a[i][j] = a[i + n/2][j - n/2];//右下复制 34 for(register int i = k+n/2;i <= k + n - 1;i++) for(register int j = n/2 + 1;j<= n;j++) a[i][j] = a[i - n/2][j - n/2];//左下复制 35 } 36 } 37 signed main(){ 38 freopen("match.in","r",stdin); 39 freopen("match.out","w",stdout); 40 cin>>M; 41 int n = mypow(2,M); 42 a[1][1] = 1; 43 work(1,n); 44 for(register int i = 1;i <= n;i++){ 45 for(register int j = 1;j <= n;j++){ 46 printf("%lld ",a[i][j]); 47 } 48 cout<<endl; 49 } 50 return 0; 51 }

浙公网安备 33010602011771号