当前位置: 首页 > article >正文

GXUOJ-算法-第四次作业(圆排列、连续邮资、n皇后、符号三角形)

1.圆排列

问题描述

GXUOJ | 圆排列

代码解答

#include<bits/stdc++.h>

using namespace std;

int n;
int r[1000];
double x[1000];
double ans = 0x3f3f3f3f;

double calculate(){
	memset(x, 0, sizeof x);
	for(int i = 0; i < n; i++){
		for(int j = 0; j < i; j++)
			x[i] = max(x[i], x[j] + sqrt(4*r[i]*r[j]));
	}
	double low = 0x3f3f3f3f, high = - 0x3f3f3f3f;
	for(int i = 0; i < n; i++){
		low = min(low, x[i] - r[i]);
		high = max(high, x[i] + r[i]);
	}
	return high - low;
}

int main(){
	cin >> n;
	for(int i = 0; i < n; i++)
		cin >> r[i];
	do{
		ans = min(ans, calculate());
	}while(next_permutation(r, r + n));
	printf("%.2lf", floor(ans * 100)/100);
}

但是这个算法考虑的全是圆相切的情况,并没有考虑如下的情况

圆排列问题详解(原理+代码)_对n个圆的最优排列问题,深度优先遍历其排列树所需要的辅助空间-CSDN博客

 代码更改

#include<bits/stdc++.h>
using namespace std;
const int MAXLEN =1000;
double r[MAXLEN];//存放圆排列的半径
double x[MAXLEN];//存放圆排列的圆心横坐标
double best_r[MAXLEN];//用来记录结果
int N;//输入圆的个数 
double minlen=1000;

void compute(){
    //找到了一个排列 且此半径排列存放在数组r中
    double low=0,high=0;
    for(int i=1;i<=N;i++){//算出每一个圆的左边界和右边界
        if(x[i]-r[i] < low) low = x[i]-r[i];
        if(x[i]+r[i] > high) high = x[i]+r[i]; 
    }
    if(high-low<minlen){
        minlen=high-low;//更新最小长度
        for(int i=1;i<=N;i++) best_r[i]=r[i];//记录最小排列
    }
}

double center(int t){//计算圆心坐标 
	double x_max=0;
	for(int j=1;j<t;j++){//t=1的时候 第一个圆不计算 横坐标记为0 
		double x_value=x[j]+2.0*sqrt(r[t]*r[j]);
		if(x_value>x_max) x_max=x_value;//取最大的那个计算值 
	} 
	return x_max;
}

void backtrack(int index){
    if(index==N+1){//已经找到了一个排列
        compute();
    }
    else{
        for(int j=index;j<=N;j++){//index之前的已经排列好 index位置依次与后面的交换 
            swap(r[index],r[j]);
            double center_x=center(index);//计算当前第t个位置的横坐标
			if(center_x+r[index]+r[1]<minlen){//如果已经大于维护的最小值 则不必搜索 
				x[index]=center_x;//存入表示坐标的数组x中
				backtrack(index+1);//递归选择index+1位置 
			}
            swap(r[index],r[j]);//index选择j的情况已经结束 把他换回去 进行下一个交换 
        }
    }
}
int main(){
    cin>>N;//一共N个圆 
    for(int i=1;i<=N;i++){
        cin>>r[i];//输入所有圆的半径
    }
    backtrack(1);
    //输出结果 
    printf("%.2f",minlen-0.005); 
    
    return 0;
}

2.连续邮资

问题描述

GXUOJ | 连续邮资

代码解答

#include<bits/stdc++.h>
using namespace std;
int n, m;//n为邮票种类,m为一封信上最多贴的邮票个数
int Max;
int ans[10000];//最终答案数组

//能否用n种邮票,面值在x数组中,最多贴m张,表示出sum(是个动态规划问题,
//方法是求出dp[n][sum]看它是否小于sum,状态转移方程
//dp[i][j]=min(dp[i-1][j-k*x[i]]+k)(其中dp[i][j]表示用到第i种邮票,
//表示邮资为j的最少邮票
bool panduan(int x[], int n, int sum){
	
    //dp[i][j]来表示使用前i种邮票凑出邮资j所需的最少邮票数
    int dp[15][1005]={0};
    
    for (int i = 1; i <= sum; i++)
        dp[1][i] = i;
    for (int i = 2; i <= n; i++){
        for (int j = 1; j <= sum; j++){
            dp[i][j] = 9999;
            for (int k = 0; k <= j / x[i]; k++)
                dp[i][j] = min(dp[i][j], dp[i - 1][j - x[i] * k] + k);
        }
    }
    if (dp[n][sum] > m)
        return false;
    return true;
}
void DFS(int x[], int cur, int max){
	
    if (cur == n){//如果已经得出了n种邮票
        if (max > Max){//并且它的最大值已经大于当前最大邮资数
            Max = max;
            for (int i = 1; i <= cur; i++)
                ans[i] = x[i];//更新答案数组
        }
        return;
    }
    
    for (int next = x[cur] + 1; next <= max + 1; next++)//如果还没得到n中邮票,那么从x[cur]+1~max+1选一个作为下一个邮资,因为max+1没法表示,所以必定到max+1为止
    {
        x[cur + 1] = next;
		//接下来是重点,用种类为cur+1,数目分别为x[1..cur+1]的邮票,最多使用m张,
		//能否表示出大于max的某个数
		int newMax=max;
        for (int i = max + 1; i <= m * x[cur + 1]; i++){
		//这个数最少要为max+1(不然没有意义了),最多是x[cur+1]*m
            if (panduan(x, cur + 1, i) == 0)//如果成立
                break;
            newMax=i;
    	}
        if (newMax> max)//如果至少让最大值更新了一次
            DFS(x, cur + 1, newMax);
    }

}
int main()
{
   	cin >> n >> m;
    Max = 0;
    int x[1000]={0};//中间传递的数组,存储当前的邮票值的解
    
    x[1] = 1;
    DFS(x, 1, m);//x存储当前的解,cur表示当前传递到第几种邮票,max表示目前能表示到的最大值
   
    for (int i = 1; i <= n; i++)
        cout<<ans[i] <<" ";
    cout << endl;
	cout << Max;
    return 0;
}

3.n皇后问题

问题描述

GXUOJ | n皇后问题

代码解答

#include <bits/stdc++.h>
using namespace std;
const int N = 20;

// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径

int n;
char g[N][N];
bool col[N], dg[N], udg[N];
int result = 0;

void  dfs(int u) {
    // u == n 表示已经搜了n行,故输出这条路径
    if (u == n) {
        result++;
        return;
    }

    // 枚举u这一行,搜索合法的列
    int x = u;
    for (int y = 0; y < n; y++)
        // 剪枝(对于不满足要求的点,不再继续往下搜索)  
        if (col[y] == false && dg[y - x + n] == false && udg[y + x] == false) {
            col[y] = dg[y - x + n] = udg[y + x] = true;
            dfs(x + 1);
            col[y] = dg[y - x + n] = udg[y + x] = false;
        }
}

int main() {
    cin >> n;
    dfs(0);
    cout << result;
    return 0;
}

4.符号三角形

问题描述

GXUOJ | 符号三角形

代码解答

#include <bits/stdc++.h>
using namespace std;

// n 表示符号三角形第一行的元素个数
//	cnt 用于积累符号三角形中1的元素个数 
int n, cnt = 0; 
// sum 用于统计满足条件的符号三角形的数量
int sum = 0; 
// p 数组用于存储符号三角形,p[i][j] 表示第 i 行第 j 列的元素
int p[25][25]; 

// 回溯函数,t 表示当前处理到符号三角形第一行的第 t 个位置
void back(int t) {
    // 剪枝条件:如果当前已经确定的 1 的数量超过了总数的二分之一,或者剩余位置全为 1 时 1 的数量仍超过总数的二分之一,就返回
    // n*(n + 1)/4 是因为整个符号三角形元素总数为 n*(n + 1)/2 ,1 的数量如果超过一半,就不可能满足 0 和 1 数量相等
    // t*(t - 1)/2 - cnt 表示假设剩余位置全为 1 时 1 的数量
    //前t行总元素为 t*(t+1)/2 ,减去 t和 cnt 假设剩余位置全为 1 时 1 的数量 
    if (cnt > n * (n + 1) / 4 || t * (t - 1) / 2 - cnt > n * (n + 1) / 4) return; 
    // 如果已经处理完符号三角形第一行的所有元素,说明成功构建了一个符号三角形 
    if (t > n) sum++; 
    else
        // 尝试在当前位置放置 0 或 1
        for (int i = 0; i < 2; i++) { 
            // 在符号三角形第一行的第 t 个位置放置 i
            p[1][t] = i; 
            // 更新当前已确定的 1 的数量
            cnt += i; 
            // 根据上一行的元素确定当前行的元素
            for (int j = 2; j <= t; j++) { 
                // 通过异或运算确定当前位置的元素,这里用异或模拟符号三角形的生成规则
                p[j][t - j + 1] = p[j - 1][t - j + 1] ^ p[j - 1][t - j + 2]; 
                // 更新当前已确定的 1 的数量
                cnt += p[j][t - j + 1]; 
            }
            // 递归处理下一个位置
            back(t + 1); 
            // 回溯,恢复之前的状态,减去当前行已确定的 1 的数量
            for (int j = 2; j <= t; j++) { 
                cnt -= p[j][t - j + 1]; 
            }
            // 回溯,恢复之前的状态,减去当前位置放置的 1 的数量
            cnt -= i; 
        }
}

int main() {
    cin >> n; 
    // 从符号三角形第一行的第一个位置开始回溯
    back(1); 
    cout << sum; 
    return 0;
}

 

没有注释版本

#include<bits/stdc++.h>
using namespace std;

int n,sum,cnt;
int p[25][25];

void back(int t){
	if(cnt>(n+1)*n/4|| t*(t-1)/2-cnt>(n+1)*n/4)	return;
	if(t>n) sum++;
	else{
		for(int i=0;i<2;i++){
			p[1][t]=i;
			cnt+=i;
			for(int j=2;j<=t;j++){
				p[j][t-j+1]=p[j-1][t-j+1]^p[j-1][t-j+2];
				cnt+=p[j][t-j+1]; 
			}
			back(t+1);
			for(int j=2;j<=t;j++)
				cnt-=p[j][t-j+1];
			cnt-=i;
		}
	}
}
int main(){
	cin>>n;
	back(1);
	cout<<sum;
	return 0;
}


http://www.kler.cn/a/461090.html

相关文章:

  • 【数据仓库金典面试题】—— 包含详细解答
  • 商用车自动驾驶,迎来大规模量产「临界点」?
  • 4. C语言 变量
  • java中统一异常处理,如何实现全局异常处理,@RestControllerAdvice 注解实现统一异常处理
  • enzymejest TDD与BDD开发实战
  • P5289 [十二省联考 2019] 皮配 做题记录
  • 「下载」智慧文旅运营综合平台解决方案:整体架构,核心功能设计
  • Rabbitmq追问2
  • UniApp 组件的深度运用
  • 【时时三省】(C语言基础)动态内存函数calloc
  • 活动安排.
  • nginx-nginx的缓存集成
  • Tube Qualify弯管测量系统在汽车管路三维检测中的应用
  • 08.VSCODE:内嵌MSYS2及三方库UTF8-CPP的实战
  • Spring 框架——@Async 注解
  • 可以突破合同相对性原则,不包括借用资质及多层转包和违法分包关系中的实际施工人
  • 【华为OD-E卷-统计匹配的二元组个数 100分(python、java、c++、js、c)】
  • 大语言模型遇上寻路算法:LLM-A*如何让路径规划效率提升50%?
  • 高效管理 Nginx 的利器:nginxWebUI 指南和 Docker 部署安装过程
  • 又一年。。。。。。
  • QT_BEGIN_NAMESPACE 和 QT_END_NAMESPACE (二)
  • 基于Spring Boot + Vue3实现的在线汽车保养维修预约管理系统源码+文档
  • MySQL 并行复制:提升数据同步速度的秘密武器
  • Maven (day04)
  • Type-C接口台式显示器:LDR6021引领新潮流
  • 激光雷达点云语义分割——Polarseg环境配置