POJ--2112--Optimal Milking【Floyd+Dinic+二分答案】

本文讨论了一个关于挤奶器和牛群优化分配的问题,通过使用Floyd算法处理多源最短路径,结合二分查找和Dinic算法优化容量网络流,找到满足条件的最小路径解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:http://poj.org/problem?id=2112

题意:有k个挤奶器,编号1~k,c头牛,编号k+1~k+c,每个挤奶器最多能给m头牛挤奶,给你一个k+c的邻接矩阵,要求每头牛都能挤奶并且要求c头牛需要走的所有路程中的最大路程最小,求这个最小的路。


思路:

1. 先用floyd处理出多源最短路

2. 用二分枚举答案的可能,初始上限应该为(200+30)*200,但是我这么开T了,可能因为代码太挫,改到1000,卡着时间过了,只能说poj数据弱了。后来看别人的代码,和我的做法一样但是用了邻接表,就能设上限为40000了。在二分中:

(1)构造容量网络,以0点为源点,到每头牛的容量为1,以n+1点为汇点,每个挤奶器到汇点的容量为m,当然反过来也可以,因为源点和汇点的流量是相等的(等于c)。对于每头牛和每个挤奶器之间的距离,如果比枚举的距离还大,则容量为0,否则容量为1。

(2)Dinic找出网络最大流,很明显最大流最大是c,当最大流是c的时候是一种答案,但不一定是最优,更新二分上限,如果最大流没达到c,则更新下限。


这是做完POJ2391知道了Dinic优化,改进后的写法,优化了三个地方:容量网络改为邻接表、Dinic优化、二分上限从floyd中返回,157MS ,我原以为Dinic优化应该是效率提高的主要原因,把Dinic优化去掉单纯用邻接表,266MS,原来邻接表才是这道题效率提高的主要原因,但是Dinic优化还是很有用的。如果floyd再加个剪枝,可以跑110MS

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 200100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define mod 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct node{
    int u,w,next;
}edge[MAXN];
int head[350],e[350][350];
int dist[350];
int cnt,n,m,k,c,src,sink;
void add_edge(int a,int b,int c){
    edge[cnt].u = b;
    edge[cnt].w = c;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}
int floyd(){
    int i,j,k;
    int maxm = 0;
    for(k=1;k<=n;k++){
        for(i=1;i<=n;i++){
            if(e[i][k]==INF)    continue;
            for(j=1;j<=n;j++){
                if(e[k][j]!=INF&&e[i][k]+e[k][j]<e[i][j]){
                    e[i][j] = e[i][k] + e[k][j];
                    if(e[i][j]>maxm)    maxm = e[i][j];
                }
            }
        }
    }
    return maxm;
}
void build_graph(int minm){
    int i,j;
    memset(head,-1,sizeof(head));
    cnt = 0;
    for(i=1;i<=k;i++){
        add_edge(i,n+1,m);
        add_edge(n+1,i,0);
    }
    for(i=k+1;i<=n;i++){
        add_edge(0,i,1);
        add_edge(i,0,0);
    }
    for(i=k+1;i<=n;i++){
        for(j=1;j<=k;j++){
            if(e[i][j]<=minm){
                add_edge(i,j,1);
                add_edge(j,i,0);
            }
        }
    }
}
int bfs(){
    int i,j;
    memset(dist,-1,sizeof(dist));
    queue<int>q;
    q.push(0);
    dist[0] = 1;
    while(!q.empty()){
        int t = q.front();
        q.pop();
        for(i=head[t];i!=-1;i=edge[i].next){
            if(dist[edge[i].u]==-1&&edge[i].w){
                dist[edge[i].u] = dist[t] + 1;
                q.push(edge[i].u);
            }
        }
    }
    if(dist[n+1]!=-1)    return 1;
    else    return 0;
}
int dfs(int u,int delta){
    int i,j;
    int dd;
    if(u==n+1)  return delta;
    for(i=head[u];i!=-1;i=edge[i].next){
        if(dist[edge[i].u]==dist[u]+1&&edge[i].w&&(dd = dfs(edge[i].u,min(edge[i].w,delta)))){
            edge[i].w -= dd;
            edge[i^1].w += dd;
            return dd;
        }
    }
    dist[u] = -1;
    return 0;
}
int main(){
    int i,j;
    while(scanf("%d%d%d",&k,&c,&m)!=EOF){
        n = k + c;
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                scanf("%d",&e[i][j]);
                if(e[i][j]==0)   e[i][j] = INF;
            }
        }
        int mid, l = 0,r=floyd();
        int sum,temp;
        while(l<r){
            mid = (l+r)/2;
            sum = 0;
            build_graph(mid);
            while(bfs()){
                while(1){
                    temp = dfs(0,INF);
                    if(!temp)   break;
                    sum += temp;
                }
            }
            if(sum>=c)  r = mid;
            else    l = mid + 1;
        }
        printf("%d\n",l);
    }
    return 0;
}


之前的写法,1875MS擦边过了。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 50100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define mod 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int edge[300][300],customer[300][300];
int vis[300],dist[300][300];
int n,m,k,c;
void floyd(){
    int i,j,k;
    for(k=1;k<=n;k++){
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(edge[i][k]!=INF&&edge[k][j]!=INF&&edge[i][k]+edge[k][j]<edge[i][j])
                    edge[i][j] = edge[i][k] + edge[k][j];
            }
        }
    }
}
void build_graph(int minm){
    int i,j;
    memset(customer,0,sizeof(customer));
    for(i=1;i<=k;i++)   customer[i][n+1] = m;
    for(i=k+1;i<=n;i++) customer[0][i] = 1;
    for(i=k+1;i<=n;i++){
        for(j=1;j<=k;j++){
            if(edge[i][j]<=minm) customer[i][j] = 1;
        }
    }
}
int bfs(){
    int i,j;
    memset(vis,0,sizeof(vis));
    memset(dist,0,sizeof(dist));
    queue<int>q;
    q.push(0);
    vis[0] = 1;
    while(!q.empty()){
        int t = q.front();
        q.pop();
        for(i=0;i<=n+1;i++){
            if(!vis[i]&&customer[t][i]){
                vis[i] = 1;
                dist[t][i] = 1;
                q.push(i);
            }
        }
    }
    if(vis[n+1])    return 1;
    else    return 0;
}
int dfs(int u,int delta){
    int i,j,s;
    if(u==n+1)  return delta;
    s = delta;
    for(i=0;i<=n+1;i++){
        if(dist[u][i]){
            int dd = dfs(i,min(customer[u][i],delta));
            customer[u][i] -= dd;
            customer[i][u] += dd;
            delta -= dd;
        }
    }
    return s - delta;
}
int main(){
    int i,j;
    while(scanf("%d%d%d",&k,&c,&m)!=EOF){
        n = k + c;
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                scanf("%d",&edge[i][j]);
                if(edge[i][j]==0)   edge[i][j] = INF;
            }
        }
        floyd();
        int mid, l = 0, r = 10000;
        int sum;
        while(l<r){
            mid = (l+r)/2;
            sum = 0;
            build_graph(mid);
            while(bfs())    sum += dfs(0,INF);
            if(sum==c)  r = mid;
            else    l = mid + 1;
        }
        printf("%d\n",l);
    }
    return 0;
}


<think>好的,用户问的是关于HCI_LE_Enhanced_Connection_Complete,我需要先理解这个术语。HCI指的是蓝牙的Host Controller Interface,LE代表低功耗蓝牙,也就是BLE。Enhanced Connection Complete应该是一个特定的HCI事件,用于通知主机连接已经完成,并且可能包含更多信息。 首先,我应该回忆蓝牙核心规范中的相关内容。特别是版本5.0之后,蓝牙引入了增强连接完成事件,用来提供更多的连接参数和状态信息。这个事件和传统的LE Connection Complete事件的区别可能在于支持的扩展功能,比如更详细的连接参数、PHY类型或者数据传输方向等信息。 接下来需要确认这个事件的结构。通常,HCI事件的数据格式包括事件码、参数长度、状态、连接句柄等。增强版本可能添加了更多字段,比如使用的PHY(物理层)、连接间隔、从机延迟、监督超时等参数。此外,可能还包括角色(中央或外设)、对端地址类型和地址等信息。 然后要考虑用户可能的背景。用户可能是开发蓝牙应用的工程师,或者在进行蓝牙协议分析时遇到了这个事件。他们需要了解这个事件的作用、何时触发、携带的信息以及如何解析。因此,回答中需要包含事件的结构、用途、触发场景和示例数据解析,以帮助用户实际应用。 同时要确保回答符合用户的要求:结构清晰,分步骤说明,使用中文,数学公式正确应用。比如在解释连接参数的计算时,可能需要用行内公式,如连接间隔为$1.25ms \times interval$,这里需要用$...$包裹。如果有独立的公式,比如超时计算,可能需要用$$...$$,不过在这个主题中可能较少涉及复杂公式,但需注意语法正确。 另外,需要验证信息的准确性。参考蓝牙核心规范文档,确认事件码是否为0x3E,子事件码是否为0x0A。检查参数列表是否正确,比如Connection_Handle、Role、Peer_Address_Type等字段的存在及其顺序。 可能还需要比较传统和增强版事件的差异,比如增强事件是否支持扩展广播、更高的数据速率(如LE 2M PHY或Coded PHY)等。这些信息对用户理解增强功能的重要性有帮助。 最后,整理回答的结构:先定义事件,然后触发时机,参数详细说明,与其他事件的区别,应用场景和示例解析。这样用户能逐步理解,并应用到实际开发或分析中。同时要确保语言简洁明了,避免过于技术化的术语,或在必要时进行解释。</think>HCI_LE_Enhanced_Connection_Complete 是蓝牙低功耗(BLE)协议中一个重要的**主机控制器接口(HCI)事件**,用于通知主机(Host)一个低功耗连接已成功建立。以下从技术角度分步解析: --- ### 1. **事件定义** - **事件类型**:属于蓝牙核心规范 v5.0 及更高版本引入的**增强型连接完成事件**。 - **事件码**:`0x3E`(表示 HCI LE Meta Event),子事件码为 `0x0A`。 - **作用**:提供比传统 `LE Connection Complete` 事件更详细的连接参数和状态信息,支持扩展广播和周期性广播特性。 --- ### 2. **触发时机** 当蓝牙控制器(Controller)完成以下操作时触发: - 作为**中央设备(Central)**发起连接请求并成功建立连接。 - 作为**外围设备(Peripheral)**接受来自中央设备的连接请求。 --- ### 3. **事件参数结构** 事件通过数据包传递,参数格式如下(按顺序): | 字段名 | 长度(字节) | 描述 | |--------|--------------|------| | `Subevent_Code` | 1 | 固定为 `0x0A` | | `Status` | 1 | 连接状态(`0x00` 表示成功) | | `Connection_Handle` | 2 | 连接句柄,用于后续通信标识 | | `Role` | 1 | 设备角色(`0x00`:外围设备,`0x01`:中央设备) | | `Peer_Address_Type` | 1 | 对端地址类型(公共地址/随机地址) | | `Peer_Address` | 6 | 对端设备的蓝牙地址 | | `Local_Resolvable_Private_Address` | 6 | 本地可解析私有地址(若使用) | | `Peer_Resolvable_Private_Address` | 6 | 对端可解析私有地址(若使用) | | `Connection_Interval` | 2 | 连接间隔(单位:$1.25ms$) | | `Peripheral_Latency` | 2 | 从机延迟(允许跳过的连接事件数) | | `Supervision_Timeout` | 2 | 监督超时(单位:$10ms$) | | `Master_Clock_Accuracy` | 1 | 主设备时钟精度 | --- ### 4. **与传统事件的区别** 传统 `LE Connection Complete` 事件(子事件码 `0x01`)缺少以下增强信息: - 不支持**可解析私有地址(RPA)**的传递。 - 不包含**本地和对端地址的解析信息**。 - 无法处理扩展广播和周期性广播场景。 --- ### 5. **关键参数解析** - **连接间隔(Connection Interval)**: 计算公式:$T_{\text{conn}} = \text{Connection\_Interval} \times 1.25ms$ 例如:若值为 $40$,则 $T_{\text{conn}} = 50ms$。 - **监督超时(Supervision Timeout)**: 计算公式:$T_{\text{supervision}} = \text{Supervision\_Timeout} \times 10ms$ 必须满足:$T_{\text{supervision}} > (1 + \text{Peripheral\_Latency}) \times T_{\text{conn}}$。 --- ### 6. **应用场景** - **调试与监控**:通过解析事件参数验证连接参数协商是否合理。 - **动态调整连接参数**:根据 `Connection_Interval` 和 `Peripheral_Latency` 优化功耗或吞吐量。 - **隐私保护**:通过解析 `Local/Peer_Resolvable_Private_Address` 支持私有地址机制。 --- ### 7. **示例数据解析** 假设收到以下 HCI 数据包(十六进制): ``` 3E 2A 0A 00 01 00 01 00 80AABBCCDDEE 80FFEEDDCCBB 801122334455 00 28 00 00 0A 00 ``` - **Status**: `0x00`(成功) - **Connection_Handle**: `0x0001` - **Role**: `0x00`(外围设备) - **Peer_Address**: `AABBCCDDEE`(类型为随机地址) - **Connection_Interval**: `0x0028` → $40 \times 1.25ms = 50ms$ --- ### 总结 HCI_LE_Enhanced_Connection_Complete 是 BLE 连接建立的关键事件,通过提供扩展参数支持更复杂的应用场景。开发者在实现低功耗蓝牙协议栈或调试连接问题时,需重点关注其参数定义与计算逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值