强连通分量与缩点
/*
Time: 1.31
Worker: Blank_space
Source: #10091. 「一本通 3.5 例 1」受欢迎的牛
强连通分量 缩点 统计入度
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
vector <int> e[A];
int n, m, t, dfn[A], low[A], st[A], cnt, top, d[A], sum, ans, siz[A], out[A];
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int min(int x, int y) {return x < y ? x : y;}
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u;
for(int i = 0, lim = e[u].size(); i < lim; i++)
{
int v = e[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!d[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
sum++;
while(st[top] != u) {siz[sum]++; d[st[top--]] = sum;}
siz[sum]++; d[st[top--]] = sum;
}
}
/*----------------------------------------函数*/
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read();
e[x].push_back(y);
}
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
for(int i = 0, lim = e[u].size(); i < lim; i++)
{
int v = e[u][i];
if(d[u] != d[v]) out[d[u]]++;
}
for(int i = 1; i <= sum; i++) if(!out[i]){if(t) {puts("0"); return 0;} t = i;}
printf("%d", siz[t]);
return 0;
}
/*
Time: 1.31
Worker: Blank_space
Source: #10092. 「一本通 3.5 例 2」最大半连通子图
*/
/*--------------------------------------------*/
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
vector <int> e[B], _e[B];
int n, m, mod, dfn[B], vis[B], low[B], siz[B], st[B], top, cnt, sum, d[B], dep[B], f[B], in[B];
bool _vis[B];
queue <int> q;
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int min(int x, int y) {return x < y ? x : y;}
int max(int x, int y) {return x > y ? x : y;}
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u; _vis[u] = 1;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(_vis[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
sum++;
while(st[top] != u) {_vis[st[top]] = 0; siz[sum]++; d[st[top--]] = sum;}
siz[sum]++; _vis[st[top]] = 0; d[st[top--]] = sum;
}
}
/*----------------------------------------函数*/
int main()
{
// freopen("semi2.in", "r", stdin);
n = read(); m = read(); mod = read();
for(int i = 1; i <= m; i++)
{
int u = read(), v = read();
e[u].push_back(v);
}
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(d[u] != d[v])
_e[d[u]].push_back(d[v]), in[d[v]]++;
}
for(int i = 1; i <= sum; i++) if(!in[i])
q.push(i), dep[i] = siz[i], f[i] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 0; i < _e[u].size(); i++)
{
int v = _e[u][i];
in[v]--;
if(!in[v]) q.push(v);
if(vis[v] == u) continue;
vis[v] = u;
if(dep[v] < dep[u] + siz[v]) dep[v] = dep[u] + siz[v], f[v] = f[u];
else if(dep[v] == dep[u] + siz[v]) f[v] = (f[v] + f[u]) % mod;
}
}
int ans = 0, maxdep = 0;
for(int i = 1; i <= sum; i++)
if(maxdep < dep[i]) maxdep = dep[i], ans = f[i];
else if(dep[i] == maxdep) ans = (ans + f[i]) % mod;
printf("%d\n%d\n", maxdep, ans);
return 0;
}
/*
Time: 1.31
Worker: Blank_space
Source: #10093. 「一本通 3.5 练习 1」网络协议
任务a 强连通分量 缩点 没有入度的点的个数
任务b 即 使得缩点后的图构成一个强连通分量
最优方案是从出度为0的点向入度为0的点引边
边的数量即是入度为0的边的数量与出度为0的边的数量的较大值
注意特殊情况 可能整个图就是一个强联通分量
*/
/*--------------------------------------------*/
#include<cstdio>
#include<vector>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
vector <int> e[110];
int n, m, dfn[110], low[110], st[110], top, cnt, siz[110], in[110], out[110], d[110], sum, sin, sout;
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int min(int x, int y) {return x < y ? x : y;}
int max(int x, int y) {return x > y ? x : y;}
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!d[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
sum++;
while(st[top] != u) d[st[top--]] = sum;
d[st[top--]] = sum;
}
}
/*----------------------------------------函数*/
int main()
{
n = read();
for(int i = 1; i <= n; i++)
while(scanf("%d", &m) && m)
e[i].push_back(m);
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
for(int i = 0; i < e[u].size(); i++)
if(d[u] != d[e[u][i]]) out[d[u]]++, in[d[e[u][i]]]++;
for(int i = 1; i <= sum; i++)
{
if(!in[i]) sin++;
if(!out[i]) sout++;
}
if(sum == 1) printf("%d\n0", sin);
else printf("%d\n%d", sin, max(sin, sout));
return 0;
}
/*
Time: 1.31
Worker: Blank_space
Source: #10094. 「一本通 3.5 练习 2」消息的传递
缩点 入度为0的点的个数
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
vector <int> e[1010];
int n, dfn[1010], low[1010], st[1010], top, cnt, d[1010], sum, ans, in[1010];
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!d[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
sum++;
while(st[top] != u) d[st[top--]] = sum;
d[st[top--]] = sum;
}
}
/*----------------------------------------函数*/
int main()
{
n = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
int x = read();
if(x) e[i].push_back(j);
}
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(d[u] != d[v]) in[d[v]]++;
}
for(int i = 1; i <= sum; i++) if(!in[i]) ans++;
printf("%d", ans);
return 0;
}
/*
Time: 1.31
Worker: Blank_space
Source: #10095. 「一本通 3.5 练习 3」间谍网络
缩点 缩的过程中维护该强连通分量中能用的点的最小值
判断是否能取用所有入度为0的强联通分量以及费用
注意 输出的点的编号也要是最小的
再套一层拓扑试试
还是锅掉了
参照题解修码...
*/
/*--------------------------------------------*/
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#define emm(x) memset(x, 0x3f, sizeof x)
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
vector <int> e[3010];
int n, p, r, _ans = INF, dfn[3010], low[3010], st[3010], val[3010], top, cnt, d[3010], a[3010], t[3010], sum, ans, in[3010];
bool flag;
queue <int> q;
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u;
for(int i = 0; i < e[u].size(); i++)
{
int v = e[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!d[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
sum++;
while(st[top] != u) {if(a[st[top]]) val[sum] = min(val[sum], a[st[top]]); else t[sum] = st[top]; d[st[top--]] = sum;}
if(a[st[top]])val[sum] = min(val[sum], a[st[top]]); else t[sum] = min(t[sum], st[top]); d[st[top--]] = sum;
}
}
/*----------------------------------------函数*/
int main()
{
n = read(); p = read();
for(int i = 1; i <= p; i++) {int x = read(); a[x] = read();}
r = read(); emm(val); emm(t);
for(int i = 1; i <= r; i++)
{
int x = read(), y = read();
e[x].push_back(y);
}
for(int i = 1; i <= n; i++) if(!dfn[i] && a[i]) tarjan(i);
for(int i = 1; i <= n; i++) if(!dfn[i]) {printf("NO\n%d", i); return 0;}
for(int u = 1; u <= n; u++)
for(int i = 0; i < e[u].size(); i++)
if(d[u] != d[e[u][i]]) in[d[e[u][i]]]++;
for(int i = 1; i <= sum; i++)
{
if(in[i]) continue;
ans += val[i];
}
printf("YES\n%d", ans);
return 0;
}
/*
Time: 2.1
Worker: Blank_space
Source: #10096. 「一本通 3.5 练习 4」抢掠计划
强连通分量 缩点 建图 跑最长路
每一个强联通分量中可以取走所有点的值
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int FFF = 0x8fffffff;
/*------------------------------------常量定义*/
struct edge {int v, w;};
vector <int> G1[B << 3];
vector <edge> G2[B << 3];
int n, m, s, p, a[B << 3], dfn[B << 3], low[B << 3], st[B << 3], top, cnt, sum, t[B << 3], _cnt, d[B << 3];
ll val[B << 3], ans, dis[B << 3];
bool vis[B << 3];
queue <int> q;
/*------------------------------------变量定义*/
inline int read() {
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 ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt; st[++top] = u;
for(int i = 0; i < G1[u].size(); i++)
{
int v = G1[u][i];
if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
else if(!d[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
sum++;
while(st[top] != u) {d[st[top]] = sum; val[sum] += a[st[top--]];}
d[st[top]] = sum; val[sum] += a[st[top--]];
}
}
/*----------------------------------------函数*/
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
int x = read(), y = read();
G1[x].push_back(y);
}
for(int i = 1; i <= n; i++) a[i] = read();
s = read(); p = read();
for(int i = 1; i <= p; i++) t[++_cnt] = read();
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
for(int i = 0; i < G1[u].size(); i++)
{
int v = G1[u][i];
if(d[u] != d[v]) G2[d[u]].push_back((edge){d[v], val[d[v]]});
}
dis[d[s]] = val[d[s]]; q.push(d[s]);
while(!q.empty())
{
int u = q.front(); q.pop(); vis[u] = 0;
for(int i = 0; i < G2[u].size(); i++)
{
int v = G2[u][i].v, w = G2[u][i].w;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
if(!vis[v]) {q.push(v); vis[v] = 1;}
}
}
}
for(int i = 1; i <= _cnt; i++) ans = max(ans, dis[d[t[i]]]);
printf("%lld", ans);
return 0;
}
第七个单独拿出来了