当前位置: 首页 > news >正文

信息学奥赛一本通 1511:【SCOI2011】糖果 | 洛谷 P3275 [SCOI2011] 糖果

【题目链接】

ybt 1511:【SCOI2011】糖果
洛谷 P3275 [SCOI2011] 糖果

【题目考点】

1. 图论:差分约束系统
  • 求变量的最大值:
    构造不等式形如: x a − x b ≤ c x_a-x_b\le c xaxbc,对应图中一条从顶点b到顶点a的权值为c的有向边。求图中最短路径,即可得到 x x x的一组解。
    如果图中存在负环则无解。
  • 求变量的最小值:
    构造不等式形如: x a − x b ≥ c x_a-x_b\ge c xaxbc,对应图中一条从顶点b到顶点a的权值为c的有向边。求图中最长路径,即可得到 x x x的一组解。
    如果图中存在正环则无解。
2. 图论:强连通分量 缩点 tarjan算法
3. 图论:有向无环图动规 拓扑排序

【解题思路】

x i x_i xi表示第i个小朋友分到的糖果
要想知道老师最少需要准备的糖果数,需要得到
x 1 ≥ c 1 x_1\ge c_1 x1c1
x 2 ≥ c 2 x_2\ge c_2 x2c2

x n ≥ c n x_n\ge c_n xncn
这一不等式组中 c 1 , . . . , c n c_1,...,c_n c1,...,cn的值,
需要建立类似 x i − x j ≥ c x_i-x_j\ge c xixjc的不等式构成的不等式组。
对于不等式 x i − x j ≥ c x_i-x_j\ge c xixjc,在图中建立一条从顶点j到顶点i权值为c的边,这样的一条边记作<j,i,c>。
每次循环输入X, a, b

  1. 如果 X = 1 X=1 X=1,则 x a = x b x_a = x_b xa=xb,转为不等式 x a − x b ≥ 0 x_a-x_b\ge 0 xaxb0 x b − x a ≥ 0 x_b-x_a\ge 0 xbxa0
    建边<b,a,0>, <a,b,0>。
  2. 如果 X = 2 X=2 X=2,则 x a < x b x_a<x_b xa<xb,即 x b − x a ≥ 1 x_b-x_a\ge 1 xbxa1,建边<a,b,1>。
  3. 如果 X = 3 X=3 X=3,则 x a ≥ x b x_a\ge x_b xaxb,即 x a − x b ≥ 0 x_a-x_b\ge 0 xaxb0,建边<b,a,0>。
  4. 如果 X = 4 X=4 X=4,则 x a > x b x_a> x_b xa>xb,即 x a − x b ≥ 1 x_a-x_b\ge 1 xaxb1,建边<b,a,1>。
  5. 如果 X = 5 X=5 X=5,则 x a ≤ x b x_a\le x_b xaxb,即 x b − x a ≥ 0 x_b-x_a\ge 0 xbxa0,建边<a,b,0>。

题中提到,每个小朋友都要分到糖果,因此有
x 1 ≥ 1 x_1\ge 1 x11, x 2 ≥ 1 x_2\ge 1 x21, …, x n ≥ 1 x_n \ge 1 xn1

设超级源点顶点0,顶点0到顶点0的最长路径长度为0,因此 x 0 = 0 x_0=0 x0=0
所以上述不等式组可以写为
x 1 − x 0 ≥ 1 x_1-x_0\ge 1 x1x01
x 2 − x 0 ≥ 1 x_2-x_0\ge 1 x2x01

x n − x 0 ≥ 1 x_n-x_0\ge 1 xnx01
建边<0,1,1>, <0,2,1>,…<0,n,1>。
求出从顶点0到每个其他顶点的最长路径,即可得到 x 1 , . . . , x n x_1,...,x_n x1,...,xn的一组解。
本题顶点数能达到 1 0 5 10^5 105,边数也可以达到 1 0 5 10^5 105,如果使用spfa算法求单源最长路,最差情况下时间复杂度为 O ( V E ) O(VE) O(VE)(V为顶点数,E为边数), V E VE VE最大为 1 0 10 10^{10} 1010,会超时。
本题可以考虑使用拓扑排序求单源最长路。
首先调用tarjan算法将原图g缩点,得到缩点后的图tg。
原图g中一个强连通分量中的边一定处于该强连通分量内的一个环中。
由以上分析可知,每条边的权值都大于等于0,不存在负权边。
因此如果一个强连通分量内存在正权边,由于其他的边都是非负的,那么该正权边所在的由该强连通分量内的边所构成的环一定是正权环。
如果该图存在正权环,则无法找到 x x x的一组解,即不能满足小朋友们的要求,输出-1,结束程序。
实际上,如果不存在正权环,该图中每个强连通分量中的边的权值都为0。
对缩点后的图tg进行拓扑排序动规求最长路
dis[i]表示从源点到顶点i的最长路径长度
当顶点u访问邻接点v时
存在一条从源点到顶点u再到顶点v的,长度为dis[u]+w的路径。
如果源点到顶点u的最长路径长度加上顶点u到顶点v的边权w,大于源点到顶点v的最长路径长度。
那么源点到顶点v的最长路径长度就是源点到顶点u的最长路径长度加上顶点u到顶点v的边权w。
dis[v] = max(dis[v], dis[u]+w)
在拓扑排序的过程中执行状态转移方程,求出dis数组。
scc[i]是原图g中顶点i所在强连通分量的编号,也就是在缩点后的图中的顶点编号。
因为顶点i所在强连通分量中各顶点之间的边的权值都为0,源点到一个强连通分量中各顶点的最长路径长度相同。
原图g中源点0到顶点i的最长路径长度,就是在缩点后的图中源点scc[0]到顶点scc[i]的最长路径长度。
将原图g中源点到每个顶点的最长路径长度加和,即为老师至少要准备的糖果数。

复杂度分析

顶点数为V,即题中的n,边数为E,图中边的数量大体为 k + n k+n k+n
建图 O ( V + E ) O(V+E) O(V+E)
调用tarjan算法 O ( V + E ) O(V+E) O(V+E)
缩点建图 O ( V + E ) O(V+E) O(V+E)
拓扑排序 O ( V + E ) O(V+E) O(V+E)
整体时间复杂度为 O ( V + E ) O(V+E) O(V+E),语句执行次数为 1 0 5 10^5 105量级

【题解代码】

解法1:差分约束系统

#include <bits/stdc++.h>
using namespace std;
#define N 100005
struct Edge
{int v, w;
};
vector<Edge> g[N], tg[N];
int n, k, dis[N], degIn[N];
long long sum;
bool inQue[N], inStk[N];
int dfn[N], low[N], ts, scc[N], sn;
stack<int> stk;
void tarjan(int u)
{int t;dfn[u] = low[u] = ++ts;stk.push(u);inStk[u] = true;for(Edge e : g[u]){int v = e.v;if(dfn[v] == 0){tarjan(v);low[u] = min(low[u], low[v]);}else if(inStk[v])low[u] = min(low[u], dfn[v]);} if(dfn[u] == low[u]){++sn;do{t = stk.top();stk.pop();inStk[t] = false;scc[t] = sn;}while(t != u);}
}
void topoSort()
{queue<int> que;que.push(scc[0]);while(!que.empty()){int u = que.front();que.pop();for(Edge e : tg[u]){int v = e.v, w = e.w;dis[v] = max(dis[v], dis[u]+w);if(--degIn[v] == 0)que.push(v);			}}
}
int main()
{int x, a, b;cin >> n >> k;for(int i = 1; i <= n; ++i)//每个小朋友都分到糖,至少有1块糖,xi >= 1 => xi-x0 >= 1g[0].push_back(Edge{i, 1});for(int i = 1; i <= k; ++i){cin >> x >> a >> b;if(x == 1)//xa == xb => xa-xb >= 0 , xb-xa>=0{g[a].push_back(Edge{b, 0});g[b].push_back(Edge{a, 0});}else if(x == 2)//xa < xb => xb-xa > 0 => xb-xa >= 1g[a].push_back(Edge{b, 1});	else if(x == 3)//xa >= xb => xa-xb >= 0g[b].push_back(Edge{a, 0});else if(x == 4)//xa > xb => xa-xb > 0 => xa-xb >= 1g[b].push_back(Edge{a, 1});else if(x == 5)//xa <= xb => xb-xa >= 0g[a].push_back(Edge{b, 0});}for(int i = 0; i <= n; ++i) if(dfn[i] == 0)tarjan(i);for(int u = 0; u <= n; ++u)for(Edge e : g[u]){int v = e.v, w = e.w;if(scc[u] == scc[v])//强连通分量中有正权边,一定有正权环 {if(w > 0) {cout << -1;return 0;}}else{tg[scc[u]].push_back(Edge{scc[v], w});degIn[scc[v]]++;}}topoSort();for(int i = 1; i <= n; ++i)sum += dis[scc[i]];cout << sum;return 0;
}

相关文章:

  • 单片机嵌入式滤波算法库
  • 3.2.3 掌握RDD转换算子 - 5. 合并算子 - union()
  • 人工智能可信度新突破:MIT改进共形分类助力高风险医学诊断
  • AI领域的MCP(Model-Centric Paradigm)
  • vue 中如何使用region?
  • 一、Redis快速入门
  • 《社交应用架构生存战:React Native与Flutter的部署容灾决胜法则》
  • 关于Bearer Token
  • IBM BAW(原BPM升级版)使用教程第五讲
  • k8s术语之Horizontal Pod Autoscaling
  • PlatformIO
  • RSS 2025|斯坦福提出「统一视频行动模型UVA」:实现机器人高精度动作推理
  • 结合Splash与Scrapy:高效爬取动态JavaScript网站
  • k8s术语之job
  • 使用mermaidchart 显示graph LR
  • OCCT中的布尔运算
  • C++GO语言微服务和服务发现
  • C++GO语言微服务基础技术①
  • Qt/C++面试【速通笔记八】—Qt的事件处理机制
  • 深入理解二叉树(2)
  • 我驻苏丹使馆建议在苏中国公民尽快撤离
  • 优化网络营商环境,上海严厉打击涉企网络谣言、黑灰产等违法犯罪
  • 谢晖不再担任中超长春亚泰队主教练:战绩不佳主动请辞
  • 汪海涛评《线索与痕迹》丨就虚而近实
  • 体坛联播|国米淘汰巴萨晋级欧冠决赛,申花击败梅州避免连败
  • 五角大楼要裁一批四星上将