• 一本通tarjan题目


    基本上都是板子, 还没做完

    loj

    缩点

    10091 受欢迎的牛

    缩点后出度为$ 0 $的点就是欢迎的牛,超过一个点则不存在

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 10000 + 50;
    const int M = 50000 + 50;
    struct node {
        int next, to;
    } edge[M];
    int cnt, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
    int n, m, col, top, tot;
    int cd[N], color[N], Stack[N], low[N], dfn[N], visited[N], sum[N];
    // namespace newgraph{
    //	int cnt, head[N];
    //	struct node{ int next, to; }edge[M];
    //	inline void add(int from, int to) { edge[++cnt] = (node){head[from], to}, head[from] = cnt;} }
    //}
    void tarjan(int u) {
        Stack[++top] = u, dfn[u] = low[u] = ++tot, visited[u] = 1;
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (!dfn[v])
                tarjan(v), low[u] = min(low[u], low[v]);
            else if (visited[v])
                low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            color[u] = ++col, sum[col]++, visited[u] = 0;
            while (Stack[top] != u) {
                color[Stack[top]] = col;
                sum[col]++;
                visited[Stack[top--]] = 0;
            }
            top--;
        }
    }
    int main() {
        cin >> n >> m;
        for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), add(u, v);
        for (int i = 1; i <= n; i++)
            if (!dfn[i])
                tarjan(i);
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = edge[j].next)
                if (color[i] != color[edge[j].to])
                    cd[color[i]]++;
        int ans = 0, sky;
        for (int i = 1; i <= col; i++)
            if (!cd[i])
                ans++, sky = i;
        if (ans == 1)
            cout << sum[sky];
        else
            puts("0");
        return 0;
    }
    

    10093 网络协议

    缩点后入度为零的点为第一问,$ max(rd, cd) $ 为第二问。
    原因大概就是 形成的 $ DAG $ , 是由几条单向的链合成的, 每条链都要收尾连成环, 故取max

    10094 消息的传递

    模板

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1100;
    const int M = N * N;
    struct node {
        int next, to;
    } edge[M];
    int cnt, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
    int dfn[N], low[N], visited[N], Stack[N], color[N], rd[N];
    int tot, top, col;
    int n, ans;
    void tarjan(int u) {
        dfn[u] = low[u] = ++tot, Stack[++top] = u, visited[u] = 1;
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (!dfn[v])
                tarjan(v), low[u] = min(low[u], low[v]);
            else if (visited[v])
                low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            color[u] = ++col, visited[u] = 0;
            while (Stack[top] != u) {
                color[Stack[top]] = col;
                visited[Stack[top--]] = 0;
            }
            top--;
        }
    }
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                int x;
                scanf("%d", &x);
                if (x)
                    add(i, j);
            }
        }
        for (int i = 1; i <= n; i++)
            if (!dfn[i])
                tarjan(i);
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = edge[j].next)
                if (color[i] != color[edge[j].to])
                    rd[color[edge[j].to]]++;
        for (int i = 1; i <= col; i++)
            if (!rd[i])
                ans++;
        cout << ans;
        return 0;
    }
    

    10095 间谍网络

    缩点后入度为零的点才可以收买,但判断是否有解时神经病了,看的题解。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3e3 + 50;
    const int M = 8e3 + 50;
    const int inf = 1e9 + 7;
    struct node {
        int next, to;
    } edge[M];
    int cnt, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
    int n, p, r;
    int cost[N], bribe[N], dfn[N], low[N], color[N], Stack[N], visited[N], rd[N];
    int tot, top, col;
    void tarjan(int u) {
        Stack[++top] = u, low[u] = dfn[u] = ++tot, visited[u] = 1;
        for (int i = head[u]; i; i = edge[i].next) {
            int v = edge[i].to;
            if (!dfn[v])
                tarjan(v), low[u] = min(low[u], low[v]);
            else if (visited[v])
                low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            color[u] = ++col, visited[u] = 0;
            bribe[col] = cost[u];
            while (Stack[top] != u) {
                color[Stack[top]] = col;
                bribe[col] = min(bribe[col], cost[Stack[top]]);
                visited[Stack[top--]] = 0;
            }
            top--;
        }
    }
    int main() {
        cin >> n >> p;
        for (int i = 1; i <= n; i++) cost[i] = bribe[i] = inf;
        for (int i = 1; i <= p; i++) {
            int a, b;
            scanf("%d%d", &a, &b);
            cost[a] = b;
        }
        cin >> r;
        for (int i = 1; i <= r; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
        }
        for (int i = 1; i <= n; i++)
            if (!dfn[i] && cost[i] != inf)
                tarjan(i);
        for (int i = 1; i <= n; i++)
            if (!dfn[i])
                return printf("NO
    %d", i), 0;
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = edge[j].next)
                if (color[i] != color[edge[j].to])
                    rd[color[edge[j].to]]++;
        int ans = 0;
        for (int i = 1; i <= col; i++)
            if (!rd[i])
                ans += bribe[i];
        cout << "YES" << '
    ' << ans;
        return 0;
    }
    

    10096 抢掠计划

    缩点,建造新图,跑最长路,中途记录答案

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 5e5+50;
    const int M = 5e5+50;
    struct node{ int next, to; }edge[M];
    int cnt, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node) {head[from], to}, head[from] = cnt; }
    int dfn[N], low[N], visited[N], Stack[N], color[N], rd[N], sum[N], cost[N], bar[N], new_bar[N];
    int tot, top, col;
    int n, m, ans, s, p;
    void tarjan(int u) {
    	dfn[u] = low[u] = ++tot, Stack[++top] = u, visited[u] = 1;
    	for(int i = head[u]; i; i = edge[i].next) {
    		int v = edge[i].to;
    		if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
    		else if(visited[v]) low[u] = min(low[u], dfn[v]);
    	}
    	if(low[u] == dfn[u]) {
    		color[u] = ++col, visited[u] = 0;
    		sum[col] = cost[u], new_bar[col] = bar[u];
    		while(Stack[top] != u) {
    			int t = Stack[top];
    			color[t] = col;
    			sum[col] += cost[t];
    			visited[t] = 0;
    			new_bar[col] += bar[t];
    			top--;
    		}
    		top--;
    	}
    }
    namespace new_graph{
    	struct node{ int next, to; }edge[M];
    	int cnt, head[N];
    	inline void add(int from, int to) 
    	{ edge[++cnt] = (node) {head[from], to}, head[from] = cnt; }	
    	int dis[N];
    	queue<int> q;
    	void spfa() {
    		q.push(color[s]); dis[color[s]] = sum[color[s]];
    		while(!q.empty()) {
    			int u = q.front(); q.pop();
    			for(int i = head[u]; i; i = edge[i].next) {
    				int v = edge[i].to;
    				if(dis[v] < dis[u] + sum[v]) {
    					dis[v] = dis[u] + sum[v];
    					if(new_bar[v]) ans = max(ans, dis[v]);
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    int main() {
    	cin>>n>>m;
    	for(int i = 1, a, b; i <= m; i++) scanf("%d%d", &a, &b), add(a, b);
    	for(int i = 1; i <= n; i++) scanf("%d",&cost[i]);
    	cin>>s>>p;
    	for(int i = 1, x; i <= p; i++) scanf("%d",&x), bar[x] = 1;
    	for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    	for(int i = 1; i <= n; i++) 
    		for(int j = head[i]; j; j = edge[j].next) 
    			if(color[i] != color[edge[j].to]) new_graph::add(color[i], color[edge[j].to]);
    	new_graph::spfa();
    	cout<<ans;
    	return 0;
    }
    

    割点和桥

    10098 分离的路径

    无向缩点后必然是一棵树。要求成为一个边双图。
    统计树上度数为1的点,即叶节点,$ ans = (leaf + 1) / 2 $ .
    证明还请自行百度。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5e3 + 50;
    const int M = 1e4 + 50;
    struct node {
        int next, to;
    } edge[M << 1];
    int cnt = 1, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node){ head[from], to }, head[from] = cnt; }
    int tot, col, top;
    int dfn[N], low[N], Stack[N], color[N], rd[N];
    int n, m, ans;
    void tarjan(int u, int pre) {
        dfn[u] = low[u] = ++tot, Stack[++top] = u;
        for (int i = head[u]; i; i = edge[i].next) {
            if (i == (pre ^ 1))
                continue;
            int v = edge[i].to;
            if (!dfn[v])
                tarjan(v, i), low[u] = min(low[u], low[v]);
            else
                low[u] = min(low[u], dfn[v]);
        }
        if (low[u] == dfn[u]) {
            color[u] = ++col;
            while (Stack[top] != u) color[Stack[top--]] = col;
            top--;
        }
    }
    int main() {
        cin >> n >> m;
        for (int i = 1, a, b; i <= m; i++) {
            scanf("%d%d", &a, &b);
            add(a, b), add(b, a);
        }
        tarjan(1, 0);
        for (int i = 1; i <= n; i++)
            for (int j = head[i]; j; j = edge[j].next)
                if (color[edge[j].to] != color[i])
                    rd[color[edge[j].to]]++, rd[color[i]]++;
        for (int i = 1; i <= col; i++)
            if (rd[i] == 2)
                ans++;
        cout << (ans + 1) / 2;
        return 0;
    }
    

    10099 矿场搭建

    题解

    10100 网络

    板子不说了

    10101 嗅探器

    $ n <= 100$ ,暴力就能过
    正解建议看luogu题解

    10102 旅游航道

    割边板子不说了

    10103 电力

    题解here

    10104 Blockade

    很好的一道题目。
    对于非割点,删掉后产生的贡献为$ 2 * (n - 1) ( 对于割点,就是满足) low >= dfn $ 的子树 $ size $ 相乘起来;同时搜索树的父节点也会形成一部分,即$ (n - sum - 1) * sum $

    更详细的解释可以看洛谷题解。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5+20;
    const int M = 5e5+50;
    struct node{ int next, to;} edge[M<<1];
    int cnt, head[N];
    inline void add(int from, int to) {edge[++cnt] = (node) {head[from], to}, head[from] = cnt; }
    int low[N], size[N], dfn[N], tot, n, m; 
    long long ans[N];
    void tarjan(int u) {
    	low[u] = dfn[u] = ++tot,size[u] = 1; int sum = 0;
    	for(int i = head[u]; i; i = edge[i].next) {
    		int v = edge[i].to;
    		if(!dfn[v]) {
    			tarjan(v),low[u] = min(low[u], low[v]);
    			size[u] += size[v];
    			if(low[v] >= dfn[u]) {
    				ans[u] += 1LL * sum * size[v];
    				sum += size[v];
    			}
    		}else low[u] = min(low[u], dfn[v]);
    	}
    	ans[u] += 1LL* sum * (n - sum  - 1);
    }
    int main() {
    	cin>>n>>m;
    	for(int i = 1, a, b; i <= m; i++) scanf("%d%d", &a, &b), add(a, b), add(b, a);
    	for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    	for(int i = 1; i <= n; i++) printf("%lld
    ",1LL * (ans[i] + n - 1) * 1LL * 2);
    	return 0;
    }
    
  • 相关阅读:
    maven工程下的“run as application”
    Spark机器配置计算
    数学思路
    关联和依赖
    spark数据倾斜
    windows的DOS窗口如何修改大小
    MySQL的索引创建、删除
    使用composer命令创建laravel项目命令详解
    Windows平台查看端口占用情况
    使用composer安装laravel
  • 原文地址:https://www.cnblogs.com/skkyk/p/12181894.html
Copyright © 2020-2023  润新知