我看到 @来日方长 (第一篇题解)中,判断缩点后的出度是靠
if(id[w]!=id[u]) {
du[id[w]]++;//遍历每一个点并记录出度
}
但是,如果在强连通分量中有两个点指向分量外的一个点。
如果按题解的算法来,算出缩点后出度为2,但是实际上是1,这不就错了吗?
另外,我考虑了一种算法
void rebuild() {
rebuilt.resize(idx + 1);
for(int i = 1; i <= n; i++) {
for(auto j : g[i]) {
rebuilt[belong[i]].push_back(belong[j]);
}
}
for(int i = 1; i <= idx; i++) {
sort(rebuilt[i].begin(), rebuilt[i].end());
rebuilt[i].erase(std::unique(rebuilt[i].begin(), rebuilt[i].end()), rebuilt[i].end());
}
}
belong是节点编号对应强连通分量编号的关系。先暴力加边,然后排序去重rebuilt是重建后图的名字,g是原图的名字。 但是错了,48分。 这是我wa的完整代码
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <bitset>
class Popular {
std::vector<int> belong;
std::vector<std::vector<int>> g;
std::vector<std::vector<int>> rebuilt;
int n = 0, m = 0, ans = 0, idx = 0;
void tarjan() {
std::vector<int> dfn(n + 1), low(n + 1), stk;
std::vector<bool> in_stk(n + 1);
int time = 0;
std::function<void(int)> dfs = [&](int pos)->void {
dfn[pos] = low[pos] = ++time;
stk.push_back(pos);
in_stk[pos]= 1;
for(auto i : g[pos]) {
if(dfn[i]== 0) {
dfs(i);
low[pos] = std::min(low[pos], low[i]);
} else if(in_stk[i]) {
low[pos] = std::min(low[pos], low[i]);
}
}
if(low[pos] == dfn[pos]) {
++idx;
while(stk.back() != pos) {
int now = stk.back();
belong[now] = idx;
in_stk[now] = false;
stk.pop_back();
}
int now = stk.back();
belong[now] = idx;
in_stk[now] = false;
stk.pop_back();
}
};
for(int i = 1; i <= n; i++) {
if(dfn[i] != 0) {
continue;
}
dfs(i);
}
}
void rebuild() {
rebuilt.resize(idx + 1);
for(int i = 1; i <= n; i++) {
for(auto j : g[i]) {
rebuilt[belong[i]].push_back(belong[j]);
}
}
for(int i = 1; i <= idx; i++) {
sort(rebuilt[i].begin(), rebuilt[i].end());
rebuilt[i].erase(std::unique(rebuilt[i].begin(), rebuilt[i].end()), rebuilt[i].end());
}
}
public:
Popular() {
using std::cin;
cin >> n >> m;
g.resize(n + 1);
belong.resize(n + 1);
for(int i = 1; i <= m; i++) {
int u, v;
cin>> u >> v;
g[u].push_back(v);
}
for(int i = 1; i <= idx; i++) {
sort(g[i].begin(), g[i].end());
g[i].erase(std::unique(g[i].begin(), g[i].end()), g[i].end());
}
}
void run() {
tarjan();
rebuild();
int cnt = 0, pos = 0;
for(int i = 1; i <= idx; i++) {
if(rebuilt[i].empty()) {
cnt++; pos = i;
}
}
if(cnt != 1) {
std::cout << '0';
} else {
cnt = 0;
for(int i = 1; i <= n; i++) {
if(belong[i] == pos) {
cnt++;
}
}
std::cerr << pos << " ok\n";
std::cout << cnt;
}
}
};
int main() {
Popular solution;
solution.run();
}
这是我按照题解判出度的方法改后, 应该 只改了判断出度有关
#include <iostream>
#include <vector>
#include <functional>
class Popular {
std::vector<int> belong;
std::vector<std::vector<int>> g;
int n = 0, m = 0, idx = 0;
void tarjan() {
std::vector<int> dfn(n + 1), low(n + 1), stk;
std::vector<bool> in_stk(n + 1);
int time = 0;
std::function<void(int)> dfs = [&](int pos) -> void {
dfn[pos] = low[pos] = ++time;
stk.push_back(pos);
in_stk[pos] = true;
for(auto i: g[pos]) {
if(dfn[i] == 0) {
dfs(i);
low[pos] = std::min(low[pos], low[i]);
} else if(in_stk[i]) {
low[pos] = std::min(low[pos], low[i]);
}
}
if(low[pos] == dfn[pos]) {
int now;
++idx;
do {
now = stk.back();
belong[now] = idx;
in_stk[now] = false;
stk.pop_back();
} while(now != pos);
}
};
for(int i = 1; i <= n; i++) {
if(dfn[i] != 0) {
continue;
}
dfs(i);
}
}
public:
Popular() {
using std::cin;
cin >> n >> m;
g.resize(n + 1);
belong.resize(n + 1);
for(int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
}
for(int i = 1; i <= idx; i++) {
sort(g[i].begin(), g[i].end());
g[i].erase(std::unique(g[i].begin(), g[i].end()), g[i].end());
}
}
void run() {
tarjan();
int cnt = 0, pos = 0;
std::vector<int> out(idx + 1);
for(int i = 1; i <= n; i++) {
for(int j : g[i]) {
if(belong[i] != belong[j]) {
out[belong[i]]++;
}
}
}
for(int i = 1; i <= idx; i++) {
if(out[i] == 0) {
cnt++;
pos = i;
}
}
if(cnt != 1) {
std::cout << '0';
} else {
cnt = 0;
for(int i = 1; i <= n; i++) {
if(belong[i] == pos) {
cnt++;
}
}
std::cout << cnt;
}
}
};
int main() {
Popular solution;
solution.run();
}
最后,这道题判断出度只是有和无的关系,理论上来说,就算这里除了问题,应该也不会导致答案错误。 所以,这个问题有没有大佬帮忙解答一下啊