POJ 3159 Candies(最短路 差分约束)

本文通过一个幼儿园分糖果的例子介绍了差分约束系统的概念,并解释了如何利用最短路径算法解决这类问题,确保每个孩子之间的糖果数量差距满足特定条件。

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

Candies
Time Limit: 1500MS Memory Limit: 131072K
Total Submissions: 31848 Accepted: 8896
Description

During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher brought the kids of flymouse’s class a large bag of candies and had flymouse distribute them. All the kids loved candies very much and often compared the numbers of candies they got with others. A kid A could had the idea that though it might be the case that another kid B was better than him in some aspect and therefore had a reason for deserving more candies than he did, he should never get a certain number of candies fewer than B did no matter how many candies he actually got, otherwise he would feel dissatisfied and go to the head-teacher to complain about flymouse’s biased distribution.

snoopy shared class with flymouse at that time. flymouse always compared the number of his candies with that of snoopy’s. He wanted to make the difference between the numbers as large as possible while keeping every kid satisfied. Now he had just got another bag of candies from the head-teacher, what was the largest difference he could make out of it?

Input

The input contains a single test cases. The test cases starts with a line with two integers N and M not exceeding 30 000 and 150 000 respectively. N is the number of kids in the class and the kids were numbered 1 through N. snoopy and flymouse were always numbered 1 and N. Then follow M lines each holding three integers A, B and c in order, meaning that kid A believed that kid B should never get over c candies more than he did.

Output

Output one line with only the largest difference desired. The difference is guaranteed to be finite.

Sample Input

2 2
1 2 5
2 1 4
Sample Output

5
Hint

32-bit signed integer type is capable of doing all arithmetic.
Source

POJ Monthly–2006.12.31, Sempr

用到的知识:

  • 邻接表
  • spfa
  • 差分约束
  • 堆栈优化

今天听学长讲课讲到了差分约束,一直不明白为什么是最短路而不是最长路。。。。以此题为例,终于理解了。
题意:有N个小朋友,给他们发糖,给M个关系ai bi ci
表示bi-ai<=ci ,问1和n间的最大差距;
假设1到N间有k条路,即有k个不等式 dn-d1<=wk 差分约束就是让这k个不等式都成立,所以只能取wk的最小值才能让k个都成立,是最短路。不由得感叹自己真是个蠢货。。。。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 30010
#define inf 0x3f3f3f3f3f3f
using namespace std;
typedef long long ll;
int m,n;
int cnt=0;
ll dis[maxn];
struct Node
{
    int fr;
    int to;
    ll l;
    int next;
}e[maxn*5];
int head[maxn*5];
void add(int a,int  b,ll c)
{
    e[cnt].fr=a;
    e[cnt].to=b;
    e[cnt].l=c;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
int q[maxn];
void spfa(int st)
{
    int vis[maxn];
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
    }
    vis[st]=1;
    dis[st]=0;
    int top=0;
    q[top++]=st;
    while(top)
    {
        int cur=q[--top];
        vis[cur]=0;
        for(int i=head[cur];i!=-1;i=e[i].next)
        {
            int to=e[i].to;
            if(dis[to]>dis[cur]+e[i].l)
            {
                dis[to]=dis[cur]+e[i].l;
                if(!vis[to])
                {
                    q[top++]=to;
                    vis[to]=1;
                }

            }
        }

    }

}
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));

}

int main()
{
    int a,b;
    ll l;
    scanf("%d%d",&n,&m);
    init();
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%I64d",&a,&b,&l);
        add(a,b,l);
    }
    spfa(1);
    printf("%I64d\n",dis[n]);
    return 0;
}
<think>好的,我现在需要解决用户提出的关于如何使用Dijkstra算法解决'Candies'问题的问题。首先,我要明确用户的问题是什么。用户提到了poj3159 Candies这道题,并提到在Dijkstra算法练习中遇到了困难,一直TLE,后来发现需要使用差分约束系统,现在想了解如何用Dijkstra算法解决这个问题。 首先,我需要回忆一下这道题的具体内容。根据引用[4]和[5],Candies问题应该是一个差分约束系统的题目,通常这类问题可以通过短路算法来解决。差分约束系统通常涉及到形如xj - xi <= bk的不等式,转化为图中的边,然后求短路或者长路。 用户之前尝试用Dijkstra算法但一直超时,可能因为未优化或者条件判断不充分。现在需要详细解释如何正确应用Dijkstra算法解决这个问题,并可能涉及优化方法。 接下来,我需要整理解题步骤: 1. **问题建模**:将问题转化为图论中的短路问题。根据差分约束系统,每个约束xj - xi <= bk对应一条从i到j的有向边,权值为bk。题目要求大值,即需要找到从起点到终点的短路径,因为短路径满足所有约束条件下的大值。 2. **算法选择**:Dijkstra算法适用于非负权边的图,这里边的权值bk是正数吗?假设是的,因为糖果数量只能增加。所以Dijkstra适用,尤其是使用优先队列优化的版本,即堆优化的Dijkstra,以提高效率。 3. **图的构建**:每个小朋友对应一个节点,约束条件转化为边。例如,如果a比b多不超过c个糖果,则添加一条从b到a的边,权值为c。 4. **初始化距离数组**:起点的距离为0,其他设为无穷大。然后使用优先队列处理每个节点,更新短路径。 5. **处理TLE的问题**:用户之前可能没有使用优先队列,或者使用的是邻接矩阵导致时间复杂度过高。应该使用邻接表和优先队列来优化,减少不必要的松弛操作。 6. **代码实现**:给出具体的Python代码示例,展示如何正确实现堆优化的Dijkstra算法,处理输入数据,并输出结果。 此外,需要引用相关资料,如引用[4]提到的差分约束系统的概念,以及引用[2]中的短路算法合集,可能提到其他算法如SPFA,但本题适合Dijkstra因为权值为正。 需要注意的问题可能包括输入数据的规模,比如节点数和边数,可能导致不同的实现方法的时间复杂度不同。例如,如果节点数较大,必须使用堆优化。例如,在poj3159中,节点数可能较大,所以必须使用高效的Dijkstra实现。 现在需要将这些步骤整理成一个清晰的解答,分步骤说明,并附上代码示例。同时,确保使用正确的LaTeX格式,行内公式用$...$,独立公式用$$...$$,代码块用Python语法高亮,并生成相关问题。 后,生成相关问题,可能涉及差分约束系统、Dijkstra的优化、其他短路算法的比较等。</think>### 使用Dijkstra算法解决Candies问题的分步解析 #### 1. 问题建模:差分约束系统转化为短路 题目要求满足形如 $x_j - x_i \leq b_k$ 的约束条件,其中 $x_i$ 表示第 $i$ 个小朋友的糖果数。将其转化为图论问题: - **节点**:每个小朋友对应一个节点。 - **有向边**:约束 $x_j - x_i \leq b_k$ 对应一条从 $i$ 到 $j$ 的边,权值为 $b_k$。 - **目标**:求 $x_n - x_1$ 的大值,等价于求解从节点1到节点n的**短路径**(因为短路径保证所有约束条件成立下的大值)[^4]。 #### 2. 算法选择:堆优化Dijkstra 由于所有边权均为正数(糖果差异为正),选择**优先队列优化的Dijkstra算法**,时间复杂度为 $O(m \log n)$,适合大规模数据[^2]。 #### 3. 图的构建与初始化 - **邻接表存储**:用列表存储每个节点的出边和权值。例如,约束 $x_b - x_a \leq c$ 转化为边 `a → b`,权值 $c$。 - **距离数组初始化**:`dist[1] = 0`,其余初始化为无穷大。 #### 4. 算法核心步骤 1. 使用优先队列(小堆)按距离排序待处理节点。 2. 每次取出距离小的节点 $u$,遍历其所有邻边 $u→v$,若满足 $dist[v] > dist[u] + w(u,v)$,则更新 $dist[v]$ 并将 $v$ 加入堆。 #### 5. 代码实现(Python) ```python import heapq def dijkstra(n, edges): adj = [[] for _ in range(n+1)] # 节点编号从1开始 for a, b, c in edges: adj[a].append((b, c)) dist = [float('inf')] * (n+1) dist[1] = 0 heap = [] heapq.heappush(heap, (0, 1)) while heap: current_dist, u = heapq.heappop(heap) if current_dist > dist[u]: continue # 已存在更优路径,跳过 for v, w in adj[u]: if dist[v] > dist[u] + w: dist[v] = dist[u] + w heapq.heappush(heap, (dist[v], v)) return dist[n] # 输入处理示例 n, m = 3, 2 # 假设3个节点,2条约束 edges = [ (1, 2, 5), # x2 - x1 ≤ 5 (2, 3, 3) # x3 - x2 ≤ 3 ] print(dijkstra(n, edges)) # 输出大差值:5+3=8 ``` #### 6. 关键优化点 - **优先队列**:避免遍历所有节点,时间复杂度从 $O(n^2)$ 降为 $O(m \log n)$。 - **邻接表代替邻接矩阵**:节省空间并提升遍历效率。 - **剪枝操作**:若当前堆中取出的距离大于已记录的 `dist[u]`,直接跳过[^1]。 #### 7. 正确性验证 - **差分约束的松弛操作**:每次更新 $dist[v]$ 时,确保 $dist[v] \leq dist[u] + w(u,v)$,即满足 $x_v - x_u \leq w(u,v)$。 - **终结果**:`dist[n]` 即为 $x_n - x_1$ 的大可能值。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值