一、內容
銀河中的恆星浩如煙海,但是我們只關注那些最亮的恆星。
我們用一個正整數來表示恆星的亮度,數值越大則恆星就越亮,恆星的亮度最暗是 1。
現在對於 N 顆我們關注的恆星,有 M 對亮度之間的相對關係已經判明。
你的任務就是求出這 N 顆恆星的亮度值總和至少有多大。
輸入格式
第一行給出兩個整數 N 和 M。
之後 M 行,每行三個整數 T, A, B,表示一對恆星(A, B)之間的亮度關係。恆星的編號從 1 開始。
如果 T = 1,說明 A 和 B 亮度相等。
如果 T = 2,說明 A 的亮度小於 B 的亮度。
如果 T = 3,說明 A 的亮度不小於 B 的亮度。
如果 T = 4,說明 A 的亮度大於 B 的亮度。
如果 T = 5,說明 A 的亮度不大於 B 的亮度。
輸出格式
輸出一個整數表示結果。
若無解,則輸出 -1。
數據範圍
N≤100000,M≤100000
輸入樣例:
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
輸出樣例:
11
二、思路
- 根據題目所給關係可以建立不等式:
三、代碼
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, M = 6 * N;
struct E {int v, w, next;} e[M];
int n, m, a, b, x, len, h[N], sh[N], top, num, id[N], scc_cnt, stack[N], dfn[N], low[N], scc[N], d[N];
bool in_st[N], vis[N];
void add(int h[], int u, int v, int w) {
e[++len].v = v; e[len].next = h[u]; e[len].w = w; h[u] = len;
}
void tarjan(int u) {
dfn[u] = low[u] = ++num;
stack[++top] = u; in_st[u] = true;
for (int j = h[u]; j; j = e[j].next) {
int v = e[j].v;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (in_st[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++scc_cnt; int v;
do {
v = stack[top--]; in_st[v] = false;
scc[scc_cnt]++; id[v] = scc_cnt;
} while (u != v);
}
}
int dfs(int u) {
int ans = 0;
vis[u] = true;
for (int j = h[u]; j; j = e[j].next) {
int v = e[j].v;
if (id[u] == id[v]) ans += e[j].w;
if (vis[v] || id[u] != id[v]) continue;
ans += dfs(v);
}
return ans;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &x, &a, &b);
if (x == 1) add(h, b, a, 0), add(h, a, b, 0);
else if (x == 2) add(h, a, b, 1);
else if (x == 3) add(h, b, a, 0);
else if (x == 4) add(h, b, a, 1);
else if (x == 5) add(h, a, b, 0);
}
//建立超級源點
for (int i = 1; i <= n; i++) add(h, 0, i, 1);
tarjan(0);
//判斷是否有強連通分量 邊權大於0
bool ok = false;
for (int i = 0; i <= n; i++) {
if (dfs(i)) {
ok = true;
break;
}
}
if (ok) printf("-1");
else {
for (int u = 0; u <= n; u++) {
for (int j = h[u]; j; j = e[j].next) {
int v = e[j].v;
if (id[u] != id[v]) add(sh, id[u], id[v], e[j].w);
}
}
//根據拓撲圖進行dp
for (int u = scc_cnt; u >= 1; u--) {
for (int j = sh[u]; j; j = e[j].next) {
int v = e[j].v;
if (d[v] < d[u] + e[j].w) d[v] = d[u] + e[j].w;
}
}
ll ans = 0;
for (int i = 1; i <= scc_cnt; i++) ans += d[i] * scc[i];
printf("%lld", ans);
}
return 0;
}