SCL--二分匹配

2015-05-28 21:03:27

总结:

 

首先是跑得最快的 Hopcroft-Karp (这个算法是因为 hdu 2389 才学的..)

bool find(int p){
    for(int i = first[p]; ~i; i = e[i].next){
        int v = e[i].v;
        if(!vis[v] && dy[v] == dx[p] + 1){
            vis[v] = 1;
            if(!my[v] || find(my[v])){
                my[v] = p;
                mx[p] = v;
                return true;
            }
        }
    }
    return false;
}

int HK(){
    memset(mx,0,sizeof(mx));
    memset(my,0,sizeof(my));
    int res = 0;
    while(1){
        bool flag = false;
        while(!Q.empty()) Q.pop();
        memset(dx,0,sizeof(dx));
        memset(dy,0,sizeof(dy));
        for(int i = 1; i <= m; ++i) if(!mx[i]) Q.push(i);
        while(!Q.empty()){
            int x = Q.front(); Q.pop();
            for(int i = first[x]; ~i; i = e[i].next){
                int v = e[i].v;
                if(!dy[v]){
                    dy[v] = dx[x] + 1;
                    if(my[v]){
                        dx[my[v]] = dy[v] + 1;
                        Q.push(my[v]);
                    }
                    else flag = true;
                }
            }
        }
        if(!flag) break;
        memset(vis,0,sizeof(vis));
        for(int i = 1; i <= m; ++i)
            if(!mx[i] && find(i)) ++res;
    }
    return res;
}

 

接着是经典的 Hungary:

bool find(int p){
    for(int i = first[p]; ~i; i = e[i].next){
        int v = e[i].v;
        if(used[v] == 0){
            used[v] = 1;
            if(mat[v] == 0 || find(mat[v])){
                mat[v] = p;
                tmat[p] = v;
                return true;
            }
        }
    }
    return false;
}

int Hungary(){
    memset(mat,0,sizeof(mat));
    memset(tmat,0,sizeof(tmat));
    int res = 0;
    for(int i = 1; i <= N; ++i){
        memset(used,0,sizeof(used));
        if(find(i)) res++;
    }
    return res;
}

转载于:https://www.cnblogs.com/naturepengchen/articles/4536933.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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值