D - 稳住GCD DP

http://acm.uestc.edu.cn/#/problem/show/923

给定一堆数字,求其所有数字的gcd。

现在要删除最多的数字,使得剩下的数字的gcd和原来的一样。

设dp[i][val]表示在前i个数中,得到val这个数字所需的最小数字,怎么得到val这个数字?就是gcd得到。

dp[i][gcd]

然后转移就是

dp[i][a[i]] = 1是必然的,自己一个

枚举新数字得到新的gcd  val

dp[i][val] = min(dp[i][val], dp[i - 1][j]  + 1)

每次都要和自己比较一下,因为防止自己更小,就是dp[i][val]本来就是1,这样就不需要枚举其他数加入来了,。

//#include<stdio.h>
//int main() {
//    int i;
//    char a[10][3]= {"一","和","三","四","物","社","嗯","阶","己","嗯"};
//    for(i=0; i<10; i++)
//        printf("%s\n",a[i]);
//    return 0;
//}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
int dp[700 + 20][10000 + 20];
int a[10000 + 20];
void work() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int ans = a[1];
    for (int i = 2; i <= n; ++i) {
        ans = __gcd(ans, a[i]);
    }
    memset(dp, 0x3f, sizeof dp);
    dp[1][a[1]] = 1;
    for (int i = 2; i <= n; ++i) {
        dp[i][a[i]] = 1; //自己一直出现,一次就够
        for (int j = 1; j <= 10000; ++j) {
            if (dp[i - 1][j] != inf) {
                dp[i][j] = min(dp[i][j], dp[i - 1][j]);
                int t = __gcd(j, a[i]);
                dp[i][t] = min(dp[i][t], dp[i - 1][j] + 1);
            }
        }
    }
    cout << n - dp[n][ans] << endl;
}

int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    work();
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/liuweimingcprogram/p/5904580.html

#include <pic.h> #include <tenx_TM56M1522.h> #include "TM56M1522_bsp.h" #include "TM56M1522_OT.h" #include "TM56M1522_sfr_config.h" const unsigned char szTemp @0x0FFF=0; //Don't remove or remark this line. /*********************************************************************************/ //---------------------------------------------------------------------------// #define TM56_SCL_HIGH PA4MOD = 1; // 设置 PA4 高电平 #define TM56_SCL_LOW PA4MOD = 0; // 设置 PA4 低电平 #define TM56_SDA_HIGH PA5MOD = 1; // 设置 PA5 高电平 #define TM56_SDA_LOW PA5MOD = 0; // 设置 PA5 低电平 #define DATA_DP 0X80 #define DIS_ADDRE1 0X68 // 第一个数码管的地址 #define DIS_ADDRE2 0X6A // 第二个数码管的地址 #define DIS_ADDRE3 0X6C // 第三个数码管的地址 #define DIS_ADDRE4 0X6E // 第四个数码管的地址 #define TM_SHOWADDRE 0X48 // 显示地址 #define DATA_NULL 0X00 // 不显示 //---------------------------------------------------------------------------// unsigned char SHUM_NUM[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0X40}; //unsigned char SHUM_ADDRE[4]={0x6e,0x6c,0x6a,0x68}; // 数码管段地址 const unsigned char BADJ[8]={0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x01}; // 亮度调节 //---------------------------------------------------------------------------// signed int ADC_TEMP=0; // 用于温度数据存储和在数码管数码管上显示 //---------------------------------------------------------------------------// #define TEMPS 91 #define NTC_HIGH_PRECISION 1 //1=0.1℃ 0=1℃ unsigned int code NTCNUM[TEMPS]={ // ntc器件的数据查表 //3581,3559,3535,3511,3486,3461,3435,3408,3381,3353, //3324,3295,3266,3234,3203,3171,3138,3105,3072,3037, 3003, //0 2968,2932,2896,2859,2823,2785,2748,2710,2672,2633, 2595,2556,2517,2478,2438,2399,2360,2321,2281,2242, 2203,2164,2125,2086,2048,2009,1971,1933,1896,1858, 1822,1785,1749,1713,1678,1643,1608,1574,1540,1507, 1475,1436,1411,1380,1349,1319,1289,1260,1231,1203, 1176,1149,1122,1096,1070,1045,1021,997,974,951, 928,906,885,864,843,823,803,784,766,747, 729,712,695,678,662,646,631,616,601,587, 573,559,546,533,520,508,496,484,473,462, //451,440,430,420,410,400,391,382,373,365, //356,348,340,332,325,317,310,303,296,290, //283,277,271,265,259,253,247,242,237,231, }; /*******************************************************************************/ //================== i2c时序函数和数码管显示函数 ============================// //--------- i2c延时函数 -----------------------------------------------------// void dleay_i2c(unsigned char us) { unsigned char i; unsigned char k; k=0; for(i=0;i<us;i++) { k++; } } //--------- TM56i2c引脚初始化函数 -------------------------------------------// void tm56i2c_init(void) { // 关闭全局中断(确保原子操作) //GIE = 0; // 配置 PA4 和 PA5 为开漏模式(模式3) PA4MOD = 0x3; PA5MOD = 0x3; // 启用全局开漏功能(如需) // PINMODbits.HSINK = 1; // 恢复全局中断 //GIE = 1; // 设置引脚为输出模式 PA4MOD = 0; // PA4 设为输出 PA5MOD = 0; // PA5 设为输出 } //--------- i2c起始信号位函数 -----------------------------------------------// void TM1650i2c_start(void) { TM56_SCL_HIGH; // 确保slk和dat线都都处在释放状态 TM56_SDA_HIGH; dleay_i2c(6); TM56_SCL_HIGH; // 拉高时钟线 dleay_i2c(6); TM56_SDA_LOW; // 拉低数据线 TM56_SCL_LOW; // 将时钟线也拉低 } //--------- 判断应答位函数 --------------------------------------------------// bit TM1650_ack(void) { unsigned char ack; ack=0; TM56_SCL_HIGH; // 将PA5引脚拉高输出高电平 PA5MOD = 1; // PA5 设为输入 TM56_SCL_LOW; // 将时钟线拉低以允许数据变化 dleay_i2c(6); TM56_SCL_HIGH; // 将时钟线拉高以稳住现数据线状态 if(PA5MOD==0); // 如果PA5引脚为0,将ack置为1 ack=1; TM56_SCL_LOW; PA5MOD = 0; // PA5 设为输出 return !ack; // 返回应答位 } //--------- 发送i2c指令数据函数 ---------------------------------------------// void Send_i2cDat(unsigned char Dat) { unsigned char i; TM56_SCL_LOW; TM56_SDA_LOW; dleay_i2c(6); for(i=7;i>=0;i--) { if(Dat&(1<<i)) // 判断sda是否为高电平或低电平,从高到低 { TM56_SDA_HIGH; } else { TM56_SDA_LOW; } } dleay_i2c(6); TM56_SCL_HIGH; // 拉高时钟线以稳住sda线数据 dleay_i2c(6); TM56_SCL_LOW; // 拉低时钟线以允许sda数据变化 } //--------- i2c停止信号位函数 -----------------------------------------------// void TM1650i2c_stop(void) { TM56_SCL_HIGH; // 拉高时钟线 TM56_SDA_LOW; // 拉低数据线 dleay_i2c(6); TM56_SDA_HIGH; // 将数据线拉高 } //--------- 写入i2c指令地址函数 ---------------------------------------------// void Write_i2cAddCmd(unsigned char addre,unsigned char cmd) { dleay_i2c(200); // 器件上电先稳定一段时间 TM1650i2c_start(); // 发送开始信号 Send_i2cDat(addre); // 写入1650器件的地址 TM1650_ack(); Send_i2cDat(cmd); // 写入1650器件相应指令 TM1650_ack(); TM1650i2c_stop(); // 发送停止信号 } //--------- 1650器件显示初始化 ----------------------------------------------// void TM1650_Init(void) { tm56i2c_init(); // 进行i2c引脚功能初始化 Write_i2cAddCmd(TM_SHOWADDRE,BADJ[6]); // 显示地址,亮度为7档 Write_i2cAddCmd(DIS_ADDRE1,DATA_NULL); Write_i2cAddCmd(DIS_ADDRE2,DATA_NULL); Write_i2cAddCmd(DIS_ADDRE3,DATA_NULL); Write_i2cAddCmd(DIS_ADDRE4,DATA_NULL); } //--------- 显示温度函数 ----------------------------------------------------// void Show_Temp(unsigned int adc_temp) { if(adc_temp<0) { Write_i2cAddCmd(DIS_ADDRE1,SHUM_NUM[10]); // 显示‘-’号 adc_temp=-adc_temp; } else { Write_i2cAddCmd(DIS_ADDRE1,SHUM_NUM[adc_temp/10]); // 显示第十位温度数 } Write_i2cAddCmd(DIS_ADDRE2,SHUM_NUM[adc_temp%10]); // 始终显示个位 } //===========================================================================// //========================== ADC各函数 ======================================// //-------------------- 系统时钟初始化函数 -----------------------------------// void Sys_Init(unsigned char div ) // div:系统分频00:8分频|01:4分频|02:2分频|03:1分频 { FASTSTP=0; //启动快时钟 asm("nop"); asm("nop"); asm("nop"); CPUCKS=1; //切换到快时钟 asm("nop"); CPUPSC = div; //系统时钟分频 asm("nop"); } //------------------- adcio初始化函数 ---------------------------------------// void ADCIO_Init(void) { PB0MOD = 6; } //------------------- adc初始化函数 -----------------------------------------// void ADC_Init(void) { ADCIE = 0; //关闭ADC中断 ADCKS = 4; //Fsys/16分频 ADVREFS = 0; //参考电压vcc PA3MOD = 3; //IO口模拟输入模式 } //------------------- 获取ADC数据函数 ---------------------------------------// unsigned int GetNum_Adc(unsigned char CH) // CH为adc通道号 { unsigned char i; unsigned char ADCDATL; // adc低位 unsigned int ADCDATH; // adc高位 unsigned int adc_max=0; // 最大采样值(用于滤波) unsigned int adc_min=0XFFFF; // 采样最小值 (初始为最大值) unsigned int adc_sun=0; // 才样次数值总和(未滤波前) unsigned int Temp=0; // 单次采样临时存储 ADCHS=CH; // adc采样通道选择(寄存器) for(i=0;i<10;i++) // adc采样采集十次进行滤波 { ADST=1; // 置位adc启动位开启转换 while(ADST); // 采样完成自动置0 ADCDATH=ADCDH; // 读取高八位数据 ADCDATL=ADCTL; // 读取低四位数据 /* 数据重组(构造12位ADC值)*/ ADCDATL &= 0xF0; // 屏蔽低4位,保留高4位(0bXXXX0000) ADCDATL >>= 4; // 右移4位得到有效低4位(0b0000XXXX) ADCDATH<<=4; // 高8位左移4位(腾出空间给低4位) Temp = (ADCDATH + ADCDATL); // 组合成12位数值(0x0FFF最大) /* 更新极值和总和 */ adc_sun += Temp; // 累加到总和 if(Temp > adc_max) { // 检测是否为新最大值 adc_max = Temp; } if(Temp < adc_min) { // 检测是否为新最小值 adc_min = Temp; } } /*-------- 数字滤波处理 --------*/ adc_sun -= adc_min; // 去除最小异常值 adc_sun -= adc_max; // 去除最大异常值 adc_sun >>= 3; // 右移3位等效于除以8(求8次采样均值) return adc_sun; // 返回滤波后的12位有效值(0-4095) } //---------------- 二分查找函数 ---------------------------------------------// unsigned int Find_NtcNum(unsigned int list,unsigned int AdcNum) { unsigned int *list_pt; // 指向NTCNUM数组的指针 unsigned int mid=0; // 中间索引 unsigned int left=0; // 左边界索引 unsigned int right=TEMPS-1; // 右边界索引 list_pt=&list; // 获取NTCNUM数组的首地址 /*-- 边界条件检查(处理超出表格范围的情况)--*/ if(AdcNum >= *(list_pt + 0)) // 当ADC值 >= 表格第一个值(最高温度) return 0; // 直接返回最高温度索引 if(AdcNum <= *(list_pt + TEMPS - 1)) // 当ADC值 <= 表格最后一个值(最低温度) return TEMPS - 1; // 直接返回最低温度索引 /*-- 二分查找核心算法 --*/ while((right - left) > 1) // 当左右索引不相邻时继续查找 { mid = (left + right) >> 1; // 计算中间位置(等效除以2但更快) if(AdcNum == *(list_pt + mid)) // 找到精确匹配 return mid; else if(AdcNum > *(list_pt + mid)) // ADC值比中间值大(温度更低区域) right = mid; // 移动右边界(因为表格是降序排列) else if(AdcNum < *(list_pt + mid)) // ADC值比中间值小(温度更高区域) left = mid; // 移动左边界 } return left; } //---------------- 读取ADC值获取NTC温度值+线性插值 ---------------------------------------------// signed Read_NtcNum(unsigned int list[],unsigned int ADCRT,signed char BaseValue) { unsigned char index = 0; // 查表得到的索引号 unsigned int deta = 0; // 相邻表项的ADC差值(用于插值) unsigned char t = 0; // 温度插值分量(0.1℃单位) signed int result = 0; // 最终温度计算结果 /*-- 边界条件检查 --*/ if(ADCRT >= list[0]) // ADC值 >= 表格最大值(温度最低点) return BaseValue; // 直接返回起始温度(如-20.0℃) if(ADCRT <= (list[TEMPS - 1])) // ADC值 <= 表格最小值(温度最高点) { // 计算末端温度值(BaseValue + (NUM-1)*10*0.1℃) result = ((TEMPS - 1) * 10 + BaseValue); return result; // 如表格100项时返回 BaseValue+990(99.0℃) } /*-- 核心查表操作 --*/ index = Find_NtcNum(list, ADCRT);// 调用二分查找获取相邻索引 /*-- 高精度插值模式 --*/ #if NTC_HIGH_PRECISION // 计算相邻表项的ADC差值(需确保index+1不越界) deta = list[index] - list[index + 1]; // 计算温度差值分量: // (当前ADC与上边界的差值 / 总差值) * 10(转换为0.1℃单位) // 例如:ADC差值=200,当前ADC离上边界差50 → 50/200*10=2.5个0.1℃ t = 10 * (list[index] - ADCRT) / deta; #endif /*-- 合成最终温度值 --*/ // BaseValue + 索引对应温度 + 插值分量 // 例如:BaseValue=-200(-20.0℃),index=20(对应2.0℃) // 插值t=5 → 最终温度=(-200 + 200 +5)=5 → 0.5℃ result = (BaseValue + index * 10 + t); return result; // 返回0.1℃精度的温度值 } /*========================= MAIN ============================================*/ void main(void) { unsigned int temp=0; Sys_Init(2); TM1650_Init(); ADCIO_Init(); ADC_Init(); RDCTL |= 0x03; while(1) { temp=GetNum_Adc(7); ADC_TEMP=Read_NtcNum(NTCNUM,temp,-200); Show_Temp(ADC_TEMP); } } /*===========================================================================*/ 这代码有错误吗?
06-01
<think>好的,我现在需要分析用户提供的C代码是否存在语法或逻辑错误,并给出改进建议。首先,我要仔细阅读代码,理解它的功能。代码涉及I2C通信、ADC采样和温度计算,这让我想到可能涉及到传感器数据的读取和处理。首先,我会检查语法错误。比如,变量声明是否正确,函数调用是否符合规范,指针使用是否恰当,以及是否有缺少分号或括号不匹配的情况。例如,用户代码中的`MXC_ADC->ctrl`部分,可能存在位操作的问题,比如是否正确清除了`MXC_F_ADC_CTRL_ADC_CHSEL`位,然后重新设置。这里需要注意位掩码的应用是否正确,避免位域冲突。接下来是逻辑错误。例如,在I2C通信中,是否正确处理了起始和停止信号,是否有正确的延时,以及是否检查了设备的应答信号。引用[3]提到需要实现起始和停止信号函数,但用户代码中是否有调用这些函数呢?如果代码中没有正确的起始信号,可能导致通信失败。此外,ADC的配置是否正确,比如参考电压设置、采样率等,是否与硬件匹配。引用[4]中的案例展示了ADC初始化的步骤,用户代码是否遗漏了某些配置步骤?然后,查看ADC采样部分。用户代码中清除了标志位,并启用了中断,但可能没有等待转换完成就直接读取数据,这会导致读取到旧数据或错误值。正确的流程应该是启动转换,等待完成标志位,再读取数据。此外,通道选择是否正确,比如`channel`变量是否在有效范围内,否则可能导致选择错误的ADC通道。温度计算部分,需要检查数据处理是否正确。比如,从ADC读取的原始值是否经过正确的转换公式得到温度值,是否有考虑传感器的特性,如非线性或校准系数。如果代码中没有应用校准数据,计算结果可能会有偏差。改进建议方面,首先应增加错误检查,比如I2C通信是否成功,ADC转换是否完成。其次,添加注释和宏定义以提高可读性,如引用[5]提到的使用宏定义封装功能模块。另外,考虑使用硬件抽象层,增强代码的可移植性。中断处理部分需要确保临界区的保护,避免竞争条件。最后,生成相关问题,帮助用户深入理解可能的问题点,比如ADC配置是否正确,I2C协议实现是否完整,温度计算是否准确等。</think>### 代码分析及改进建议 #### 代码功能 此C代码涉及以下功能模块: 1. **ADC配置**:清除ADC完成标志、启用中断、选择ADC通道。 2. **I2C通信**:通过寄存器操作配置I2C控制参数(隐含协议操作)。 3. **温度计算**:未直接展示,但结合ADC采样和I2C通信推测涉及传感器数据采集与处理。 --- #### 语法错误检查 1. **位操作问题**: - 原代码:`ctrl_tmp &= ~(MXC_F_ADC_CTRL_ADC_CHSEL);` - 问题:若`MXC_F_ADC_CTRL_ADC_CHSEL`是位掩码而非位序号,此写法正确;但若需清除多个位,需检查掩码是否覆盖所有目标位。 - 改进:确认掩码定义,例如`MXC_F_ADC_CTRL_ADC_CHSEL`是否对应通道选择位的全部范围。 2. **中断标志清除**: - 原代码:`ADC_ClearFlags(MXC_F_ADC_INTR_ADC_DONE_IF);` - 问题:需确认`MXC_F_ADC_INTR_ADC_DONE_IF`是否为正确的标志位掩码[^1]。 --- #### 逻辑错误检查 1. **ADC通道选择逻辑**: - 原代码:`channel << MXC_F_ADC_CTRL_ADC_CHSEL_POS` - 问题:若`channel`超出ADC支持的最大通道数,会导致寄存器写入错误。 - 改进:添加通道范围校验,例如: ```c if (channel > MAX_ADC_CHANNEL) return ERROR_CODE; ``` 2. **I2C协议完整性**: - 问题:代码中未显式调用I2C起始/停止信号函数(如`I2C_Start()`和`I2C_Stop()`),可能违反协议时序[^3]。 - 改进:在读写操作前后添加起始/停止信号,例如: ```c I2C_Start(); // ... I2C读写操作 I2C_Stop(); ``` 3. **ADC采样与中断冲突**: - 问题:启用中断(`MXC_ADC->intr |= ...`)但未实现中断服务函数(ISR),可能导致未处理的中断堆积。 - 改进:若使用轮询模式,应移除中断使能;若用中断模式,需实现ISR并清除标志。 --- #### 改进建议 1. **增强健壮性**: - 添加错误处理:检查函数返回值(如I2C读写状态、ADC配置结果)。 - 使用宏定义封装寄存器操作,提高可读性[^5],例如: ```c #define ADC_SET_CHANNEL(ch) (MXC_ADC->ctrl = (MXC_ADC->ctrl & ~CH_MASK) | ((ch) << CH_POS)) ``` 2. **优化温度计算**: - 若涉及传感器(如热电偶),需添加非线性校准或查表法。 - 示例公式(假设线性ADC): $$ T = \frac{V_{\text{ADC}} \cdot R_{\text{ref}}}{Gain} \cdot K_{\text{sensor}} $$ 3. **代码结构优化**: - 分离功能模块:将ADC、I2C、温度计算封装为独立函数。 - 添加注释说明关键步骤(如协议时序、计算公式)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值