EZ?
針對每一點都做一次 dfs 看看能不能完全走訪就好。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m, i, j, u, v;
vector<int> g[105]; // graph
int chk[105];
stack<int> dfs;
bool flag = false;
cin >> n >> m;
for (i = 0; i < m; i++) {
cin >> u >> v;
g[u].push_back(v);
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
chk[j] = 0;
}
dfs.push(i);
chk[i] = 1;
while (!dfs.empty()) {
int top = dfs.top();
dfs.pop();
for (auto k : g[top]) {
if (chk[k] == 0) {
dfs.push(k);
chk[k] = 1;
}
}
}
for (j = 0; j < n; j++) {
if (chk[j] == 0) {
break;
}
}
if (j == n) {
flag = 1;
break;
}
}
cout << (flag == true ? "Yes" : "No") << endl;
return 0;
}
因為此圖無環,也就是說,如果某一點沒有進入該點的路徑,他必為起點(不然會不到他),若有兩個以上這樣的點,則不可能是 LAN 通圖。這是其中一位同學寫的 code 寫得很乾淨。
n, m = list(map(int, input().split()))
l = [-1] * n
for i in range(m):
a, b = list(map(int, input().split()))
l[b] += 1
if l.count(-1) > 1:
print("No")
else:
print("Yes")
在建圖的時候如果有一條路叫做 u v,則必須建兩條路徑 u->v, v->u,再來從任一一點開始走訪就好。
#include <bits/stdc++.h>
using namespace std;
int n, m, i, j, u, v, cnt = 0;
vector<int> g[1005000]; // graph
int chk[1005000] = {0};
stack<int> dfs;
bool flag = false;
int main() {
cin >> n >> m;
for (i = 0; i < m; i++) {
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs.push(0);
chk[0] = 1;
while (!dfs.empty()) {
int top = dfs.top();
dfs.pop();
for (auto k : g[top]) {
if (chk[k] == 0) {
dfs.push(k);
chk[k] = 1;
}
}
}
for (j = 0; j < n; j++) {
if (chk[j] == 0) {
break;
}
}
cout << (j == n ? "Yes" : "No") << endl;
return 0;
}
有向無環圖,就算有負權重邊,也存在最長路徑
複雜度允許,直接用 bellman-ford algorithm:
#include<bits/stdc++.h>
using namespace std;
int const maxe = 6010, maxv = 510;
int V, C, E, u[maxe], v[maxe], h[maxe];
int best, d[maxv];
int main()
{
scanf("%d%d%d", &V, &C, &E);
for(int i = 0; i < E; i++) scanf("%d%d%d", &u[i], &v[i], &h[i]);
memset(d, -1, sizeof d);
d[C] = best = 0;
for(int i = 1; i < V; i++)
for(int j = 0; j < E; j++) if(~d[u[j]]) {
d[v[j]] = max(d[v[j]], d[u[j]] + h[j]);
best = max(best, d[v[j]]);
}
printf("%d\n", best);
return 0;
}
將所有路線依運送量由大排到小,再依序取邊配合 disjoint set 建立出 MST。
之後利用 LCA 求解…LCA 請自行上網查詢或參閱下方程式碼與註解@~@
pa[d][n] = 從點 n 往上找的第 2^d 個點
mn[d][n] = 從點 n 往上到 pa[d][n] 之間所有邊的最小權重
dep[n] = 點 n 在此 MST 中的深度 ( 樹根深度為 0 )
#include <bits/stdc++.h>
#define INF 1000000
using namespace std;
struct edge {
int a, b, c;
} es[1000011];
vector<edge> g[100011];
int pa[20][100011], mn[20][100011], dep[100011];
int ds[100011];
int find(int i) //disjoint set
{
if (ds[i] == i)
return i;
else
return ds[i] = find(ds[i]);
}
void unite(int a, int b) //disjoint set
{
ds[find(a)] = find(b);
}
void dfs(int i, int p, int c, int d) //DFS
{
pa[0][i] = p;
mn[0][i] = c;
dep[i] = d;
for (edge j : g[i])
if (j.b != p)
dfs(j.b, i, j.c, d + 1);
}
int lca(int a, int b) //LCA
{
if (dep[a] > dep[b]) //保證點 a 必定不比點 b 還深
swap(a, b);
int ans = INF;
for (int i = 19; i >= 0; i--) //此迴圈結束時,點 a 和點 b 深度相同
if (dep[pa[i][b]] >= dep[a]) {
ans = min(ans, mn[i][b]);
b = pa[i][b];
}
for (int i = 19; i >= 0; i--) //此迴圈結束時,點 a 和點 b 的父親會相同
if (pa[i][b] != pa[i][a]) {
ans = min(ans, mn[i][b]);
ans = min(ans, mn[i][a]);
b = pa[i][b];
a = pa[i][a];
}
if (a != b) {
ans = min(ans, mn[0][b]);
ans = min(ans, mn[0][a]);
}
return ans;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
scanf("%d%d%d", &es[i].a, &es[i].b, &es[i].c);
sort(es, es+m, [](edge a, edge b) {return a.c > b.c;}); //將邊由大到小排序
for (int i = 0; i < n; i++)
ds[i] = i;
for (int i = 0; i < m; i++) { //建立 MST
if (find(es[i].a) != find(es[i].b)) {
g[es[i].a].push_back({0, es[i].b, es[i].c});
g[es[i].b].push_back({0, es[i].a, es[i].c});
unite(es[i].a, es[i].b);
}
}
dfs(0, 0, INF, 0); // 走訪 MST
for (int i = 1; i < 20; i++)
for (int j = 0; j < n; j++)
pa[i][j] = pa[i - 1][pa[i - 1][j]];
for (int i = 1; i < 20; i++)
for (int j = 0; j < n; j++)
mn[i][j] = min(mn[i - 1][j], mn[i - 1][pa[i - 1][j]]);
int q;
scanf("%d", &q);
while (q--) {
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", lca(a, b));
}
}