zoukankan      html  css  js  c++  java
  • 【NOIP模拟题】Graph(tarjan+dfs)

    似乎我搞得太复杂了?

    先tarjan缩点然后dfs就行了QAQ。

    (我不说我被一个sb错调了半个小时。。。。不要以为缩点后dfs就可以肆无忌惮的不加特判判vis了。。

    bfs的做法:减反图,然后从大到小枚举(贪心),标记即可

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <vector>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define pii pair<int, int>
    #define mkpii make_pair<int, int>
    #define pdi pair<double, int>
    #define mkpdi make_pair<double, int>
    #define pli pair<ll, int>
    #define mkpli make_pair<ll, int>
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=1e5+10;
    int m, mx[N], LL[N], FF[N], vis[N], tot, scc, st[N], fa[N], top;
    struct Gr {
    	int ihead[N], cnt, n;
    	struct dat { int next, to; }e[N];
    	void add(int u, int v) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; }
    	void tarjan() { for1(i, 1, n) if(!FF[i]) tarjan(i); }
    	void tarjan(int x) {
    		LL[x]=FF[x]=++tot; vis[x]=1; st[++top]=x;
    		for(int i=ihead[x]; i; i=e[i].next) {
    			int y=e[i].to;
    			if(!FF[y]) {
    				tarjan(y);
    				LL[x]=min(LL[x], LL[y]);
    			}
    			else if(vis[y] && FF[y]<LL[x]) LL[x]=FF[y];
    		}
    		if(FF[x]==LL[x]) {
    			++scc;
    			int y;
    			do {
    				y=st[top--];
    				vis[y]=0;
    				fa[y]=scc;
    				mx[scc]=max(mx[scc], y);
    			} while(y!=x);
    		}
    	}
    	void dfs() { CC(vis, 0); for1(i, 1, n) if(!vis[i]) dfs(i); }
    	void dfs(int x) {
    		if(vis[x]) return; //这个我就不说了,坑。。。
    		vis[x]=1;
    		for(int i=ihead[x]; i; i=e[i].next) {
    			dfs(e[i].to);
    			mx[x]=max(mx[x], mx[e[i].to]);
    		}
    	}
    }G, g;
    
    int main() {
    	read(G.n); read(m);
    	for1(i, 1, m) { int u=getint(), v=getint(); G.add(u, v); }
    	G.tarjan();
    	g.n=scc;
    	for1(x, 1, G.n) for(int i=G.ihead[x]; i; i=G.e[i].next) if(fa[x]!=fa[G.e[i].to]) g.add(fa[x], fa[G.e[i].to]);
    	g.dfs();
    	for1(i, 1, G.n) printf("%d ", mx[fa[i]]);
    	return 0;
    }
    

      


    【题目描述】

    给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点。

    【输入格式】

    第 1 行,2 个整数 N,M。 接下来 M 行,每行 2 个整数 Ui,Vi,表示边 ⟨Ui,Vi⟩。点用 1,2,...,N 编号。

    【输出格式】

    N 个整数 A(1),A(2),...,A(N)。

    【样例输入】

    4 3

    1 2

    2 4

    4 3

    【样例输出】

    4 4 3 4

    【数据范围】

    对于 60% 的数据,1 ≤ N,K ≤ 10^3

    对于 100% 的数据,1 ≤ N,M ≤ 10^5。

  • 相关阅读:
    J2EE(一)——开发简单WEB服务器
    日报--2015年7月10日
    MVC @Html控件(转载)
    Asp.NET MVC--【Asp.net】
    附加到进程 调试技巧--【VS】
    快速阅读学习方法笔记
    匿名函数和闭包--【JavaScript】
    Repeater显示数据--[Asp.Net]
    FileUpLoad上传文件--[Asp.Net]
    35Canlender--[Asp.Net]
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4076197.html
Copyright © 2011-2022 走看看