一個含有個結點條邊的無向有權圖,判斷每個結點是否在從到的最短路徑上
輸入描述
第一行輸入一個整數,代表有組測試數據 對於每一組測試數據,第一行有個整數,接下來行每行有個整數x ,表示和之間有一條權值爲 的邊
輸出描述
對於每組測試數據,在一行中輸出個整數,第個整數代表號結點的關鍵性
代表該結點不可能出現在從到的最短路徑上
代表該結點出現在所有從到的最短路徑上
代表該結點出現在部分從到的最短路徑上
數據範圍
保證無重邊無自環且連通
輸出時每行末尾的多餘空格,不影響答案正確性
樣例輸入
2
6 7
1 2 1
2 3 1
2 4 1
2 5 2
3 5 1
4 5 2
5 6 1
4 6
1 2 1
1 3 1
1 4 2
2 3 1
2 4 1
3 4 1
樣例輸出
1 1 2 0 1 1
1 2 2 1
樣例解釋
對於第一組樣例的解釋:
對於第二組樣例的解釋:
紅點表示一定不在最短路徑上 綠點表示在所有最短路徑上 藍點表示在一部分最短路徑上
分別從節點和求單元最短路,得到每個點到節點和的最距離,。
設存儲號節點的類型,初始化爲0。
對於任意一邊,滿足且,則該邊在最短路徑上,因此令。
將所有此類邊建圖,在該圖上求割點,令割點:。
最後要單獨令。
求最短路複雜度爲,Tarjan求割點複雜度爲,因此總體時間複雜度爲。
#include<bits/stdc++.h>
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;
inline int qr() {
int f = 0, fu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')fu = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
f = (f << 3) + (f << 1) + c - 48;
c = getchar();
}
return f * fu;
}
const int N = 1e3 + 10, M = 2e5 + 10;
int head[N], ver[M << 1], Next[M << 1], edge[M << 1], tot;
int n, m, T, dfn[N], low[N], num, ans[N];
ll d1[N], d2[N];
bool v[N];
int hc[N], vc[M << 1], nc[M << 1], tc;
inline void add(int x, int y, int z) {
ver[++tot] = y;
Next[tot] = head[x];
edge[tot] = z;
head[x] = tot;
}
inline void add_c(int x, int y) {
vc[++tc] = y;
nc[tc] = hc[x];
hc[x] = tc;
}
inline void dijkstra1() {
repi(i, 1, n)v[i] = false, d1[i] = 4e18;
d1[1] = 0;
priority_queue<pair<ll, int> > q;
q.push(make_pair(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = true;
reps(x) {
int y = ver[i], z = edge[i];
if (d1[y] > d1[x] + z) {
d1[y] = d1[x] + z;
q.push(make_pair(-d1[y], y));
}
}
}
}
inline void dijkstra2() {
repi(i, 1, n)v[i] = false, d2[i] = 4e18;
d2[n] = 0;
priority_queue<pair<ll, int> > q;
q.push(make_pair(0, n));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (v[x]) continue;
v[x] = true;
reps(x) {
int y = ver[i], z = edge[i];
if (d2[y] > d2[x] + z) {
d2[y] = d2[x] + z;
q.push(make_pair(-d2[y], y));
}
}
}
}
inline void build() {
for (int i = 1; i < tot; i += 2) {
int x = ver[i], y = ver[i + 1], z = edge[i];
if (d1[x] > d1[y])swap(x, y);
if (d1[x] + z + d2[y] == d1[n])
add_c(x, y), add_c(y, x), ans[x] = ans[y] = 2;
}
}
void tarjan(int x) {
dfn[x] = low[x] = ++num;
int flag = 0;
for (int i = hc[x]; i; i = nc[i]) {
int y = vc[i];
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x]) {
flag++;
if (x != 1 || flag > 1)ans[x] = 1;
}
} else low[x] = min(low[x], dfn[y]);
}
}
int main() {
T = qr();
while (T--) {
n = qr(), m = qr();
repi(i, 1, n)head[i] = 0;
tot = 0;
while (m--) {
int x = qr(), y = qr(), z = qr();
add(x, y, z), add(y, x, z);
}
dijkstra1(), dijkstra2();
repi(i, 1, n)hc[i] = ans[i] = dfn[i] = low[i] = 0;
tc = num = 0;
build();
tarjan(1);
ans[n] = ans[1] = 1;
repi(i, 1, n)printf("%d%c", ans[i], ce(i, n));
}
return 0;
}