【知识】Topo & 有向图连通性
有向图连通性 & Topo 排序
B3644 【模板】拓扑排序 / 家谱树
#include <iostream>
using namespace std;
const int N=100005;
int du[N], h[N], e[N], ne[N],cnt;
int n;
int q[N];
void add(int a,int b){
e[++cnt] = b;
ne[cnt] = h[a];
h[a] = cnt;
}
void topo(){
int hh = 0, tt = -1;
for (int i = 1; i <= n;i++) if(!du[i])
q[++tt] = i;
while(hh<=tt){
int u = q[hh++];
for (int i = h[u]; i;i=ne[i]){
if(!--du[e[i]])
q[++tt] = e[i];
}
}
for (int i = 0; i <= tt;i++)
cout << q[i] << " ";
}
int main(){
cin >> n;
for (int i = 1; i <= n;i++){
int a;
while(cin>>a && a){
add(i, a);
du[a]++;
}
}
topo();
return 0;
}
P1347 排序
就是裸 Topo 排序。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endl
inline int rd()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
void print(int x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
return;
}
namespace Star_F
{
const int mx = 30;
int n, m;
vector<int> e[mx];
int d[mx];
int a[mx];
stack<int> s;
bool v[mx];
int mk;
bool tp(int r)
{
int sz = 0;
bool fn = true;
int t[mx];
for (int i = 0; i < n; i++)
{
t[i] = d[i];
if (!d[i])
s.push(i), v[i] = true;
}
while (!s.empty())
{
if (s.size() > 1)
fn = false;
int k = s.top();
a[sz++] = k;
s.pop();
for (int i = 0; i < e[k].size(); i++)
t[e[k][i]]--;
for (int i = 0; i < n; i++)
if (!t[i] && !v[i])
s.push(i), v[i] = true;
}
if (sz < n)
return false;
if (fn && !mk)
mk = r;
return true;
}
void Main()
{
n = rd();
m = rd();
int flaggg = 0;
FOR(i, 1, m)
{
char c[3];
scanf("%s", c);
int x = c[0] - 'A', y = c[2] - 'A';
e[x].push_back(y);
d[y]++;
if (mk)
{
cout << "Sorted sequence determined after " << mk << " relations: ";
for (int i = 0; i < n; i++)
cout << char(a[i] + 'A');
cout << ".";
flaggg = 1;
}
if (!tp(i)&&flaggg==0)
{
cout << "Inconsistency found after " << i << " relations.";
return;
}
memset(v, false, sizeof(v));
}
if (mk&&flaggg==0)
{
cout << "Sorted sequence determined after " << mk << " relations: ";
for (int i = 0; i < n; i++)
cout << char(a[i] + 'A');
cout << ".";
}
else if(flaggg==0)
{
cout << "Sorted sequence cannot be determined.";
}
}
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
return Star_F::Main(), 0;
}
Directing Edges
首先,无解的情况一定是原图有向边成环。
有解的话原图给定的有向边一定形成 DAG。
所以进行拓扑排序,对于所有无向边,让拓扑编号小的指向拓扑编号大的即可。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 200005;
int h[N], e[N], ne[N], idx;
int du[N], topo[N], tot;
int T, n, m;
void add(int u,int v){
e[++idx] = v, ne[idx] = h[u], h[u] = idx;
}
bool toposort(int n){
queue<int> q;
for (int i = 1; i <= n;i++)
if(du[i]==0)
q.push(i);
while(!q.empty()){
int x = q.front();
q.pop();
topo[x] = ++tot;
for (int i = h[x]; i;i=ne[i]){
int y = e[i];
if(--du[y]==0)
q.push(y);
}
}
if(tot<n)
return 0;
return 1;
}
void Main(){
cin >> T;
while(T--){
int n, m;
cin >> n >> m;
memset(h, 0, sizeof(h));
memset(du, 0, sizeof(du));
idx = tot = 0;
vector<PII> t;
for (int i = 1; i <= m;i++){
int opt, x, y;
cin >> opt >> x >> y;
if(opt==1){
add(x, y), du[y]++;
}
else
t.push_back({x, y});
}
if(!toposort(n)){
cout << "NO" << endl;
continue;
}
cout << "YES" << endl;
for (int i = 1; i <= n;i++){
for(int j=h[i];j;j=ne[j]){
cout << i << " " << e[j] << endl;
}
}
for (int i = 0; i < t.size();i++){
int x = t[i].fi, y = t[i].se;
if(topo[x]>=topo[y])
swap(x, y);
cout << x << " " << y << endl;
}
}
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
P2419 USACO08JAN] Cow Contest S
Floyd 算法轻松解决!
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 105;
int n, m, f[N][N], ans;
void Main(){
cin >> n >> m;
for (int i = 1; i <= m;i++){
int u, v;
cin >> u >> v;
f[u][v] = 1;
}
for (int k = 1; k <= n;k++)
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n;j++)
f[i][j] = f[i][j] | f[i][k] & f[k][j];
for (int i = 1; i <= n;i++){
int t = 1;
for (int j = 1; j <= n;j++){
if(i==j)
continue;
t = t & (f[i][j] | f[j][i]);
}
ans += t;
}
cout << ans << endl;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
P1983 [NOIP 2013 普及组] 车站分级
将不需要停靠的向需要停靠的连边,满足拓扑关系。
TopoSort 一下即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endl
inline int rd() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
void print(int x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
return;
}
namespace Star_F {
const int MAXN = 1005;
int s[MAXN][MAXN], n, m, ans, in_degree[MAXN], vis[MAXN], pd[MAXN][MAXN];
queue<pair<int, int>> q;
vector<int> g[MAXN];
inline void bfs() {
for (int i = 1; i <= n; ++i) {
if (in_degree[i] == 0)
q.push(make_pair(i, 1));
}
ans = 1;
while (!q.empty()) {
int u = q.front().first;
int val = q.front().second;
q.pop();
for (int v : g[u]) {
in_degree[v]--;
if (in_degree[v] == 0) {
q.push(make_pair(v, val + 1));
ans = max(ans, val + 1);
}
}
}
}
void Main() {
n = rd();
m = rd();
for (int i = 1; i <= m; ++i) {
s[i][0] = rd();
memset(vis, 0, sizeof(vis));
for (int j = 1; j <= s[i][0]; ++j) {
int x = rd();
s[i][j] = x;
vis[x] = true;
}
for (int j = s[i][1]; j <= s[i][s[i][0]]; ++j) {
if (vis[j]) continue;
for (int k = 1; k <= s[i][0]; ++k) {
if (!pd[j][s[i][k]]) {
in_degree[s[i][k]]++;
g[j].push_back(s[i][k]);
pd[j][s[i][k]] = true;
}
}
}
}
bfs();
cout << ans << endl;
}
}
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
return Star_F::Main(), 0;
}
P3243[ HNOI2015] 菜肴制作
最优解就是符合条件的排列中,反序列的字典序最大的排列。
定义两个拓扑序中更优的一个为“最小序”更小的拓扑序。
求证:一个 DAG 的拓扑序中“最小序”最小的的一个拓扑序,是反向字典序最大的一个。
证明:
首先,当
其次,假设结论对于
存在一条路径
特别地,有
Lemma 1:令
证明:由于 x 在拓扑序上的位置越小,最小序就越小,所以
所以
现将整个图可以分成三个子图,其点集分别为$ S-{x}
由于
因为
所以对于任意的 DAG,由数学归纳法得结论均成立。
证毕。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 100005;
int t, n, m, x, y, cnt;
int du[N], ans[N];
vector<int> G[N];
priority_queue<int> q;
void Main(){
cin >> t;
while(t--){
cin >> n >> m;
cnt = 0;
for(int i=1;i<=n;i++)
ans[i] = du[i] = 0;
for(int i=1;i<=n;i++)
G[i].clear();
for(int i=1;i<=m;i++){
cin >> x >> y;
du[x]++;
G[y].push_back(x);
}
for(int i=1;i<=n;i++)
if(!du[i])
q.push(i);
while(!q.empty()){
int u = q.top();
q.pop();
for (int i = 0; i < G[u].size(); i++){
int x = G[u][i];
du[x]--;
if(!du[x])
q.push(x);
}
ans[++cnt] = u;
}
if(cnt<n)
cout << "Impossible!";
else
for (int i = cnt; i >= 1; i--)
cout << ans[i] << " ";
cout << endl;
}
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
P3275 [SCOI2011] 糖果
先缩点,再用 TopoSort 求最长路即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10, M = 6e5 + 10;
int n, m;
int h[N], nh[N], e[M], ne[M], w[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt;
int Size[N];
void add(int h[], int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++timestamp;
stk[++top] = u, in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
++scc_cnt;
int y;
do
{
y = stk[top--];
in_stk[y] = false;
id[y] = scc_cnt;
Size[scc_cnt] ++;
} while (y != u);
}
}
int d[N], q[N];
int dp[N];
void topsort()
{
int hh = 0, tt = -1;
for (int i = 1; i <= n; i++)
if (!d[i])
q[++tt] = i, dp[i] = 1;
while (hh <= tt)
{
int t = q[hh++];
for (int i = nh[t]; ~i; i = ne[i])
{
int j = e[i];
dp[j] = max(dp[j], dp[t] + w[i]);
if (--d[j] == 0)
q[++tt] = j;
}
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while (m--)
{
int x, a,b;
scanf("%d%d%d", &x, &a, &b);
if (x == 1) add(h,a, b, 0), add(h,b, a, 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 add(h,a, b, 0);
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
memset(nh, -1, sizeof nh);
for (int i = 1; i <= n; i++)
{
for (int j = h[i]; ~j; j = ne[j])
{
int v = e[j];
int x = id[i], y = id[v];
if (x == y && w[j] == 1)
{
cout << -1;
return 0;
}
if (x != y)
{
add(nh, x, y, w[j]);
d[y] ++;
}
}
}
topsort();
ll res = 0;
for (int i = 1; i <= scc_cnt; i++)
res += (ll)dp[i] * Size[i];
cout << res;
return 0;
}
P2863 [USACO06JAN] The Cow Prom S
求点个数大于
Tarjan 缩点,判断是否大于
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, tim, top;
int h[N], e[N], ne[N], idx;
int dfn[N], low[N], s[N], ans;
bool vis[N];
void add(int u, int v){
e[++idx] = v, ne[idx] = h[u], h[u] = idx;
}
void tarjan(int x){
low[x] = dfn[x] = ++tim;
s[++top] = x; vis[x] = 1;
for (int i = h[x]; i; i = ne[i]){
int v = e[i];
if (!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
}
else if (vis[v])
low[x] = min(low[x], low[v]);
}
if (dfn[x] == low[x]){
int y;
if(x!=s[top]) ans++;
while (y = s[top--]){
vis[y] = 0;
if (x == y) break;
}
}
}
int main(){
cin >> n >> m;
for (int i = 1; i <= m; i++){
int u, v;
cin >> u >> v;
add(u, v);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
cout << ans << endl;
return 0;
}
How Many Paths?
就是搜索题,具体看代码
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 400005;
vector<int> G[N];
int n, m, o[N], vis[N], in[N];
void init(){
for (int i = 0; i <= n; i++)
vis[i] = 0;
for (int i = 0; i <= n;i++)
in[i] = 0;
}
void dfs(int x){
vis[x] = in[x] = o[x] = 1;
for (int i = 0; i < G[x].size();i++){
int y = G[x][i];
if(!vis[y])
dfs(y);
else if(in[y])
o[y] = -1;
else if(o[y]!=-1)
o[y] = 2;
}
in[x] = 0;
}
void dfs2(int x, int op){
vis[x] = 1;
if(o[x]!=-1&&o[x]!=op)
o[x] = op;
for (int i = 0; i < G[x].size(); i++){
int y = G[x][i];
if(!vis[y])
dfs2(y, op);
}
}
void Main(){
cin >> n >> m;
for (int i = 0; i <= n;i++)
G[i].clear(), o[i] = 0;
for (int i = 1; i <= m;i++){
int u, v;
cin >> u >> v;
G[u].push_back(v);
}
init();
dfs(1);
init();
for (int i = 1; i <= n;i++)
if(o[i]==2)
dfs2(i, 2);
init();
for (int i = 1; i <= n;i++)
if(o[i]==-1)
dfs2(i, -1);
for (int i = 1; i <= n;i++)
cout << o[i] << " ";
cout << endl;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
P3387 【模板】缩点
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 15;
int n, m, sum, tim, top, s;
int p[maxn], head[maxn], sd[maxn], dfn[maxn], low[maxn]; // dfn(u) 为节点 u 被搜索到时的次序编号(时间戳),low(u) 为 u 或 u 的子树能够追溯到的最早的栈中节点的次序号
int stac[maxn], vis[maxn]; // 栈 stac 用于判断当前是否在栈中
int h[maxn], in[maxn], dist[maxn];
struct EDGE
{
int to, next, from;
} edge[maxn * 10], ed[maxn * 10];
// 添加边函数,将一条从 x 到 y 的边加入邻接表
void add(int x, int y)
{
edge[++sum].next = head[x];
edge[sum].from = x;
edge[sum].to = y;
head[x] = sum;
}
// Tarjan 算法用于求解强连通分量
void tarjan(int x)
{
low[x] = dfn[x] = ++tim;
stac[++top] = x; vis[x] = 1; // 将 x 入栈,并标记 x 已访问
for (int i = head[x]; i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
}
else if (vis[v])
{
low[x] = min(low[x], low[v]);
}
}
if (dfn[x] == low[x])
{
int y;
while (y = stac[top--])
{
sd[y] = x;
vis[y] = 0;
if (x == y) break;
p[x] += p[y];
}
}
}
// 拓扑排序
int topo()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (sd[i] == i && !in[i])
{
q.push(i);
dist[i] = p[i];
}
while (!q.empty())
{
int k = q.front(); q.pop();
for (int i = h[k]; i; i = ed[i].next)
{
int v = ed[i].to;
dist[v] = max(dist[v], dist[k] + p[v]);
in[v]--;
if (in[v] == 0) q.push(v);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, dist[i]);
return ans;
}
int main()
{
scanf("%d%d", &n, &m); // 输入节点数和边数
for (int i = 1; i <= n; i++)
scanf("%d", &p[i]); // 输入每个节点的权值
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v); // 输入每条边
add(u, v); // 添加边
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i); // 对每个节点运行 Tarjan 算法
for (int i = 1; i <= m; i++)
{
int x = sd[edge[i].from], y = sd[edge[i].to];
if (x != y)
{
ed[++s].next = h[x];
ed[s].to = y;
ed[s].from = x;
h[x] = s;
in[y]++;
}
}
printf("%d", topo()); // 输出拓扑排序的结果
return 0;
}
Bertown roads
因为一个强连通分量中不好含割边,所以主要存在割边就是无解。
然后一边 Tarjan 一边记录路径就行。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 1000005;
int n, m, t, cnt;
int low[N], dfn[N];
int h[N], ne[N], e[N], idx;
bool flag, vis[N];
PII ans[N];
void add(int u,int v){
e[++idx] = v, ne[idx] = h[u],h[u] = idx;
}
void tarjan(int x,int fa){
vis[x] = 1;
low[x] = dfn[x] = ++t;
for (int i = h[x]; i;i=ne[i]){
int y = e[i];
if(!vis[y]){
tarjan(y, x);
ans[++cnt] = {x, y};
low[x] = min(low[x], low[y]);
}
if(low[y]>dfn[x]){
flag = 1;
return;
}
else if(y!=fa&&dfn[y]<dfn[x]){
low[x] = min(low[x], dfn[y]);
ans[++cnt] = {x, y};
}
}
}
void Main(){
cin >> n >> m;
while(m--){
int x, y;
cin >> x >> y;
add(x, y), add(y, x);
}
tarjan(1, 0);
if(flag){
cout << 0 << endl;
exit(0);
}
for (int i = 1; i <= cnt;i++){
cout << ans[i].fi << " " << ans[i].se << endl;
}
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
Reachability from the Capital
首先还是缩点后成为 DAG,然后对于一个入度为
注意特判起点入度为
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 5005, M = 1000005;
int ss, n, m, s[N], t, top, cnt, ans;
int h[N], e[M], ne[M], idx;
int dfn[N],low[N],id[N],in[N];
int u[N], v[N];
bool vis[N];
void add(int u,int v){
e[++idx] = v, ne[idx] = h[u], h[u] = idx;
}
void tarjan(int u){
vis[u] = 1;
dfn[u] = low[u] = ++t;
s[++top] = u;
for (int i = h[u]; i;i=ne[i]){
int v = e[i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v])
low[u] = min(low[u], low[v]);
}
if(low[u]==dfn[u]){
cnt++;
int y;
do{
y = s[top--];
vis[y] = 0;
id[y] = cnt;
} while (y != u);
}
}
void Main(){
cin >> n >> m >> ss;
for (int i = 1; i <= m;i++){
cin >> u[i] >> v[i];
add(u[i], v[i]);
}
for (int i = 1; i <= n;i++)
if(!dfn[i])
tarjan(i);
for (int i = 1; i <= m;i++){
if(id[u[i]]!=id[v[i]])
in[id[v[i]]]++;
}
for (int i = 1; i <= cnt;i++) if(!in[i])
ans++;
cout << ans - !in[id[ss]] << endl;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
/*
* ▀▀▀██████▄▄▄ _______________
* ▄▄▄▄▄ █████████▄ / \
* ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Code has no BUG! |
* ▀▀█████▄▄ ▀██████▄██ | _________________/
* ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
* ▀▀▀▄ ▀▀███ ▀ ▄▄
* ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ ______________________________
* ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ █ \\
* ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀▀▀▀█_____________________________ //
* ▌ ▐▀████▐███▒▒▒▒▒▐██▌
* ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
* ▀▀█████████▀
* ▄▄██▀██████▀█
* ▄██▀ ▀▀▀ █
* ▄█ ▐▌
* ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
* ▌ ▐ ▀▀▄▄▄▀
* ▀▀▄▄▀ ██
* \ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
* \- ▌ Name: Star_F ▀ ▀
* - ▌ (o) ▀
* /- ▌ Go Go Go ! ▀ ▀
* / ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀
*/
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!