zoukankan      html  css  js  c++  java
  • 题解 P2835 【刻录光盘】

    这个题别的大佬好像都用并查集,我觉得只需一遍 tarjan 就可以过掉,事实证明确实是这样 qwq 。


    首先读入,存边。然后对这个有向图跑一遍 tarjan 求强连通分量。然后扫描所有边,如果两个端点不在同一个强连通分量里,那么就将入度增加 1 ,最后所有入度为0的强连通分量即为所求。

    由强连通分量的基本知识我们可以知道,只要其中有一个点有了资料,那么其他的点都可以得到资料。在缩点之后,强连通分量之间又可以互相传递资料,那么就看入度为0的就行了。

    关于 tarjan出门右转不谢。

    #include<bits/stdc++.h>
    using namespace std;
    struct node {
    	int fr,to,nxt;
    } b[200*200+5];
    int cnt,h[205];
    void add(int x,int y) {
    	b[++cnt].nxt=h[x];
    	b[cnt].to=y;
    	b[cnt].fr=x;
    	h[x]=cnt;
    }
    int rd[205],id,dfn[205],vis[205],low[205],tarn,bl[205];//rd表示入度,bl表示belong于哪一个强连通分量。
    stack<int> s;
    void tarjan(int u) {//tarjan算法
    	dfn[u]=low[u]=++id;
    	s.push(u);
    	vis[u]=1;
    	for(int i=h[u]; i; i=b[i].nxt) {
    		int v=b[i].to;
    		if(!dfn[v]) {
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		} else if(vis[v]) {
    			low[u]=min(low[u],dfn[v]);
    		}
    	}
    	if(dfn[u]==low[u]) {
    		tarn++;
    		int v;
    		do {
    			v=s.top();
    			bl[v]=tarn;
    			s.pop();
    			vis[v]=0;
    		} while (u!=v);
    	}
    }
    int main() {
    	int n;
    	cin>>n;
    	for(int i=1; i<=n; i++) {
    		int x=1;
    		while(x!=0) {
    			cin>>x;
    			if(x!=0) add(i,x);
    		}
    	}
    	for(int i=1; i<=n; i++)
    		if(!dfn[i]) tarjan(i);
    	for(int i=1; i<=cnt; i++)//统计入度
    		if(bl[b[i].fr]!=bl[b[i].to]) rd[bl[b[i].to]]++;//注意加bl
    	int ans=0;
    	for(int i=1; i<=tarn; i++)
    		if(!rd[i]) ans++;
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    计算机硬件基础
    元类
    内置函数
    单例模式的三种实现方式
    字符编码
    odoo权限
    odoo api介绍
    odoo 二次开发小记不定时更新
    js与jQuery区别
    Cookie, LocalStorage 与 SessionStorage说明
  • 原文地址:https://www.cnblogs.com/ahawzlc/p/12636849.html
Copyright © 2011-2022 走看看