|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
P2476
知识点
tarjan强连通分量
思路
求出所有强连通分量, 缩点
ans1 = 入度为 0 点的总数
因为显然, 入度为 0 点没法接受到软件
ans2 = 0(scc == 1) 或 max(入度0, 出度0)
想象一条条从起点到终点的有向边, 我们的目标是把这个图变成一整个强连通图
从终点到起点连一条边, 我们就减少了一对终点和起点, 所以连接 max(入度0, 出度0) 条边就能让整个变成 scc
https://www.luogu.com.cn/article/4hmcb1h5
需要进步的地方
ans2 的解法没想出来, 做不来就手玩一些数据, 找找规律然后猜一下
当然, 可以给出一种情况大概证一下 (大概率不会
代码
- /*
- tarjan 缩点, 每个点属于的 scc 做出来
- 入度出度做出来
- ans1 = 缩点后入度0的点数
- ans2 = max(起点, 终点)
- */
- #include <bits/stdc++.h>
- using namespace std;
- const int N = 105;
- int n;
- vector<int> e[N];
- int dfn[N], low[N], tot;
- int bel[N], scc_cnt, stk[N], top;
- bitset<N> instk;
- void Tarjan(int u){
- dfn[u] = low[u] = ++tot;
- stk[++top] = u;
- instk[u] = 1;
- for(auto ed : e[u]){
- if(!dfn[ed]){
- Tarjan(ed);
- low[u] = min(low[u], low[ed]);
- continue;
- }
- if(instk[ed]){
- low[u] = min(low[u], dfn[ed]);
- }
- }
- if(dfn[u] == low[u]){
- int v;
- scc_cnt++;
- do{
- v = stk[top--];
- bel[v] = scc_cnt;
- instk[v] = 0;
- } while(u != v);
- }
- }
- int din[N], dout[N], in, out;
- int main(){
- ios::sync_with_stdio(0);
- cin.tie(0);
- cin >> n;
- for(int i = 1; i <= n; i++){
- int x;
- while(cin >> x){
- if(!x) break;
- e[i].emplace_back(x);
- }
- }
- for(int i = 1; i <= n; i++){
- if(!dfn[i]) Tarjan(i);
- }
- for(int i = 1; i <= n; i++){
- for(auto ed : e[i]){
- if(bel[i] == bel[ed]) continue;
- din[bel[ed]]++;
- dout[bel[i]]++;
- }
- }
- for(int i = 1; i <= scc_cnt; i++){
- if(!din[i]) in++;
- if(!dout[i]) out++;
- }
-
- cout << in << '\n';
- if(scc_cnt == 1) cout << 0;
- else cout << max(in, out);
- return 0;
- }
复制代码 |
|