ACWING 368 银河
ACWING 368 银河
缩点 + DAG DP + 差分约束
368. 银河 - AcWing题库
- tarjan
- 缩点
- 判原图中是否有正环,因为原图上所有边都是非负的(这也是用强连通分量解差分约束的必要条件,否则若有正权边也有负权边,若环上边权总和仍为0,则并不能说明是矛盾的), 所以如果一个强连通分量内有的边权不是 0,那么这个强连通分量中一定存在正环,所以无解
- 若不存在正环,则在 DAG 上 DP 求最长路即可
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair PII;
const int N = 1e5 + 10;
int n, m;
struct Edge
{
int to;
ll val;
};
vector G[N], E[N];
int tin[N], tim;
int scc_cnt, sz[N], id[N], low[N];
bool in_stk[N];
stack stk;
ll dist[N];
void add(int a, int b, ll c)
{
G[a].push_back({b, c});
}
void tarjan(int u)
{
tin[u] = low[u] = ++tim;
stk.push(u);
in_stk[u] = true;
for (auto [v, w] : G[u])
{
if (!tin[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (in_stk[v])
low[u] = min(low[u], tin[v]);
}
if (tin[u] == low[u])
{
++scc_cnt;
int y;
do
{
y = stk.top();
stk.pop();
in_stk[y] = false;
id[y] = scc_cnt;
sz[scc_cnt]++;
}while(y != u);
}
}
int main()
{
scanf("%d%d", &n, &m);
while(m--)
{
int t, a, b;
scanf("%d%d%d", &t, &a, &b);
if (t == 1)
add(b, a, 0), add(a, b, 0);
else if (t == 2)
add(a, b, 1);
else if (t == 3)
add(b, a, 0);
else if (t == 4)
add(b, a, 1);
else
add(a, b, 0);
}
for (int i = 1; i <= n; i++)
add(0, i, 1);
tarjan(0);
bool flag = true;
for (int u = 0; u <= n; u++)
{
for (auto [v, w] : G[u])
{
int a = id[u], b = id[v];
if (a == b && w > 0)
{
flag = false;
break;
}
else
E[a].push_back({b, w});
}
if (!flag)
break;
}
if (!flag)
{
cout << -1 << endl;
return 0;
}
for (int u = scc_cnt; u >= 1; u--)
{
for (auto [v, w] : E[u])
dist[v] = max(dist[v], dist[u] + w);
}
ll ans = 0;
for (int i = 1; i <= scc_cnt; i++)
ans += dist[i] * sz[i];
printf("%lld\n", ans);
return 0;
}