JZOJ_4735. 最小圈 (Standard IO)

本文介绍了一种使用分数规划解决有向图中寻找最小圈平均值的问题,通过将求值问题转换为可行性判断问题,并利用深搜版SPFA或DFS算法进行负环判断,以高效地找到最小平均值的圈。
Description
对于一张有向图,要你求图中最小圈的平均值最小是多少,即若一个圈经过k个节点,那么一个圈的平均值为圈上k条边权的和除以k,现要求其中的最小值
Input
第一行2个正整数,分别为n和m
   以下m行,每行3个数,表示边连接的信息
Output
一行一个数,表示最小圈的值。你的答案被视为正确当且仅当与标准答案的绝对误差不超过1e-5
Solution

新思想:分数规划,将求值问题变成可行性判断问题。

然后要利用深搜版的 SPFA或者dfs,用于判负环,来求可行性,如果是宽搜版的会被卡 TLE。

代码

 

 1 type
 2   arr=record
 3     y,next:longint;
 4     w:real;
 5   end;
 6 var
 7   bo:boolean;
 8   n,m,nm:longint;
 9   a:array [0..10001] of arr;
10   d:array [0..3001] of real;
11   ls,v:array [0..3001] of longint;
12 procedure add(x,y:longint;z:real);
13 begin
14   inc(nm);
15   a[nm].y:=y; a[nm].w:=z;
16   a[nm].next:=ls[x]; ls[x]:=nm;
17 end;
18 
19 procedure init;
20 var
21   i,x,y:longint;
22   z:real;
23 begin
24   readln(n,m);
25   nm:=0;
26   for i:=1 to m do
27     begin
28       readln(x,y,z);
29       add(x,y,z);
30     end;
31 end;
32 
33 procedure dfs(x:longint;mid:real);
34 var
35   i:longint;
36 begin
37   v[x]:=1; i:=ls[x];
38   while i<>0 do
39     with a[i] do
40       begin
41         if d[x]+w-mid<d[y] then
42           begin
43             if v[y]=1 then
44               begin
45                 bo:=true;
46                 exit;
47               end;
48             d[y]:=d[x]+w-mid;
49             dfs(y,mid);
50             if bo then exit;
51           end;
52         i:=next;
53       end;
54   v[x]:=0;
55 end;
56 
57 function pd(mid:real):boolean;
58 var
59   i:longint;
60 begin
61   for i:=1 to n do
62     begin
63       d[i]:=0; v[i]:=0;
64     end;
65   for i:=1 to n do
66     begin
67       bo:=false;
68       dfs(i,mid);
69       if bo then exit(true);
70     end;
71   exit(false);
72 end;
73 
74 procedure main;
75 var
76   l,r,mid:real;
77 begin
78   l:=-100000; r:=100000;
79   while r-l>=0.0000001 do
80     begin
81       mid:=(l+r)/2;
82       if pd(mid) then r:=mid
83                  else l:=mid;
84     end;
85   writeln(mid:0:6);
86 end;
87 
88 begin
89   init;
90   main;
91 end.

 

这个错误: ``` ../applications/drv_lcd.h:28:3: error: unknown type name '__IO' __IO uint16_t REG; ``` 表示编译器不认识 `__IO` 这个类型修饰符。这通常出现在嵌入式开发中,尤其是在使用 STM32 系列 MCU 的标准外设库(Standard Peripheral Library)或 HAL 库时。 --- ### ✅ 问题原因 `__IO` 是一个宏定义,用于表示“输入/输出”类型的变量(即 volatile 变量),常用于映射寄存器地址,确保编译器不会优化掉对这些变量的读写操作。 它通常是这样定义的: ```c #define __IO volatile ``` 而你遇到的问题是因为 `__IO` 没有被定义,所以编译器报错:**unknown type name '__IO'**。 --- ### ✅ 解决方案 你需要在头文件中包含或手动定义 `__IO` 宏。 #### ✅ 方法一:包含 CMSIS 头文件(推荐) 如果你使用的是 STM32 的开发环境(如 STM32CubeIDE、Keil、IAR 等),应包含 CMSIS 核心头文件: ```c #include "stm32fxxx_hal.h" // 根据你的芯片型号选择,如 stm32f4xx_hal.h ``` 或者更底层地: ```c #include "core_cmX.h" // X 是内核版本,如 core_cm4.h ``` 这些头文件中已经定义了 `__IO`。 例如,在 `stm32f4xx.h` 中你会看到: ```c #define __I volatile const /* 用于只读 */ #define __O volatile /* 用于只写 */ #define __IO volatile /* 用于读写 */ ``` ✅ 所以简单的修复方式是: ```c #include "stm32f4xx_hal.h" // 或对应你芯片的头文件 #include "drv_lcd.h" ``` > 注意:确保你的编译器能正确找到这些头文件路径。 --- #### ✅ 方法二:手动定义 `__IO`(适用于无 HAL 库的情况) 如果你没有使用 STM32 的标准库或 HAL,可以手动在 `drv_lcd.h` 的顶部添加定义: ```c #ifndef __IO #define __IO volatile #endif #ifndef __I #define __I volatile const #endif #ifndef __O #define __O volatile #endif ``` 然后原来的代码: ```c __IO uint16_t REG; ``` 就会被正确解释为: ```c volatile uint16_t REG; ``` --- ### ✅ 示例修复后的 `drv_lcd.h` 片段 ```c #ifndef __DRV_LCD_H #define __DRV_LCD_H // 定义 IO 类型(如果未包含 CMSIS 头文件) #ifndef __IO #define __IO volatile #endif typedef struct { __IO uint16_t REG; // 可读写的寄存器 } LCD_TypeDef; // 外设基地址映射示例 #define LCD_BASE ((uint32_t)0x60000000) #define LCD ((LCD_TypeDef *)LCD_BASE) #endif /* __DRV_LCD_H */ ``` --- ### ✅ 补充说明 - `volatile` 告诉编译器:这个变量可能会被外部(如硬件、中断)改变,禁止优化对该变量的访问。 - `__IO` 是 CMSIS(Cortex Microcontroller Software Interface Standard)标准的一部分,广泛用于 ARM Cortex-M 系列芯片开发。 --- ### ❌ 错误做法 不要直接写成: ```c volatile uint16_t REG; ``` 虽然功能等价,但为了与 STM32 官方库风格保持一致,建议使用 `__IO`,便于移植和维护。 --- ### 总结 | 方法 | 说明 | |------|------| | 包含 `stm32fxxx_hal.h` | 推荐,完整支持 STM32 生态 | | 手动定义 `__IO` | 适合轻量级项目或无库环境 | | 忽略错误 | ❌ 不可取,会导致后续编译失败 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值