有一些恒星,每个恒星有亮度。
给出一些恒星亮度的相对关系,询问这些恒星亮度总和至少有多大。
恒星最暗的亮度是 1。数值越大越亮。
关系有两个亮度相等,一个比另一个亮或暗,一个不比另一个亮或暗。
恒星的亮度
题目大意
有一些恒星,每个恒星有亮度。
给出一些恒星亮度的相对关系,询问这些恒星亮度总和至少有多大。
恒星最暗的亮度是 1 1 。数值越大越亮。
关系有两个亮度相等,一个比另一个亮或暗,一个不比另一个亮或暗。
思路
首先,有一个小坑,就是不大于其实是小于等于,不小于是大于等于,不要搞反了。
那我们会想到如果 A A 亮度小于 B B ,那 B B 的亮度可以是 A + 1 A + 1 ,如果是小于等于,那就是 A A 。
如果有多个这样的条件,为了使都满足,我们要取亮度最大的。
那如果相同,那就相同咯。
因为你考虑可以从一个地方推出来全部。
但是还有大于和大于等于啊,那你如果要直接弄的话,就不能确定一开始的点的亮度了。
那我们考虑把它转化成小于和小于等于。
如果 A A 大于 B B ,那其实等价于 B B 小于 A A 。
如果 A A 大于等于 B B ,那其实等价于 B B 小于等于 A A 。
那接着的问题就是如何确定一开始的初始点。
然后你就会发现它有环。
那让有环变成无环。。。
Tarjan 缩点!
怎么缩呢,我们考虑把 A A 小于或小于等于 B B 连一条从 A A 到 B B 的有向边。然后缩在一起的就是亮度相同的。
然后你会想到如果一个环中有一条边是由小于构成的,那就出问题了。(因为你又要求亮度相同,然后你这个地方由不能让亮度相同,那就出矛盾了)
那你就把边分成两类,可以参与缩点的和不可以参与的。
然后你也正常缩点(不然变成不了 DAG),然后建缩点后的图的时候如果一条边是不能参与缩点的,但是它的两边在缩点后属于同一个的话,就说明矛盾,就无解了。
然后你就会发现 DAG 的起始点可能不止一个,但是问题不大,就都设为亮度是 1 1 不久好了吗。
然后就会想到用拓扑序 DP,然后你在转移的时候判断一下你转移的边的类型,如果是小于的就是原来的 + 1 + 1 ,否则就是原来的。
(因为你要总和最小)
(我一开始直接无脑加一,就只有 70 70 分)
然后就可以了,具体实现可以看看代码。
代码
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
struct node {
int to, nxt, cc;
}e[1000001 ], e_[1000001 ];
ll ans;
int le_[100001 ], KK_;
int n, m, le[100001 ], KK, in[100001 ];
int op, x, y, dfn[100001 ], tmp, tot, ru[100001 ];
int low[100001 ], sta[100001 ], num[100001 ], dis[100001 ];
queue <int > q;
void add (int x, int y, int cc) {
e[++KK] = (node){y, le[x], cc}; le[x] = KK;
}
void add_ (int x, int y, int cc) {
e_[++KK_] = (node){y, le_[x], cc}; le_[x] = KK_;
}
void tarjan (int now) {
dfn[now] = low[now] = ++tmp;
sta[++sta[0 ]] = now;
for (int i = le[now]; i; i = e[i].nxt)
if (!dfn[e[i].to]) {
tarjan (e[i].to);
low[now] = min (low[now], low[e[i].to]);
}
else if (!in[e[i].to]) low[now] = min (low[now], low[e[i].to]);
if (dfn[now] == low[now]) {
in[now] = ++tot;
num[tot] = 1 ;
while (sta[sta[0 ]] != now) {
num[tot]++;
in[sta[sta[0 ]]] = tot;
sta[0 ]--;
}
sta[0 ]--;
}
}
int main () {
scanf ("%d %d" , &n, &m);
for (int i = 1 ; i <= m; i++) {
scanf ("%d %d %d" , &op, &x, &y);
if (op == 1 ) {
add (x, y, 0 );
add (y, x, 0 );
continue ;
}
if (op == 2 ) {
add (x, y, 1 );
continue ;
}
if (op == 3 ) {
add (y, x, 0 );
continue ;
}
if (op == 4 ) {
add (y, x, 1 );
continue ;
}
if (op == 5 ) {
add (x, y, 0 );
continue ;
}
}
for (int i = 1 ; i <= n; i++)
if (!dfn[i]) tarjan (i);
for (int i = 1 ; i <= n; i++)
for (int j = le[i]; j; j = e[j].nxt)
if (in[i] != in[e[j].to]) {
add_ (in[i], in[e[j].to], e[j].cc);
ru[in[e[j].to]]++;
}
else if (e[j].cc) {
printf ("-1" );
return 0 ;
}
for (int i = 1 ; i <= tot; i++)
if (!ru[i]) q.push (i), dis[i] = 1 ;
while (!q.empty ()) {
int now = q.front ();
q.pop ();
ans += 1ll * dis[now] * num[now];
for (int i = le_[now]; i; i = e_[i].nxt) {
ru[e_[i].to]--;
dis[e_[i].to] = max (dis[e_[i].to], dis[now] + e_[i].cc);
if (!ru[e_[i].to]) {
q.push (e_[i].to);
}
}
}
printf ("%lld" , ans);
return 0 ;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!