zoukankan      html  css  js  c++  java
  • codeforces732F Tourist Reform 边双联通分量

    网址:https://codeforces.com/contest/732/problem/F

    题意:

    给出一个无向图,现在要把它变成有向图,且要使得能到达城市的最少的点取最大值。

    题解:

    我们可以推理一下就知道了,我们令边双联通成环,然后桥边都指向最大的边双联通分量,则到达城市最少的点一定在最大的边双联通分量上(以下简称边双),那我们就先使用$tarjan$算法求出所有的边双。然后把这些边双先连成环,方向随意,然后把桥边连向最大的边双。我比较菜不会用$vector$成对边存储,所以就先用链式前向星。

    我第一次实现的时候真实毒瘤,我先求出桥边,然后求边双,然后把所有的边双$dfs$连成环,然后把桥边调整方向,整个代码真的巨复杂。然后后面参考了网上大佬的题解,直接找出最大的边双,然后直接在最大的边双的任意一个点开始$dfs$,然后边的方向与$dfs$相反就可以了。码力太烂了QAQ

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e5 + 5;
    struct edge
    {
    	int u, v, nxt;
    	int tp;
    };
    edge e[N << 1];
    int head[N];
    int dfn[N], low[N], n, m, clk;
    bool bri[N << 1];
    int sel[N << 1];
    int dcc[N], dcc_cnt, fver[N];
    int dcc_num[N];
    void tarjan(int u, int in_e)
    {
    	dfn[u] = low[u] = ++clk;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v;
    		if (!dfn[v])
    		{
    			tarjan(v, i);
    			low[u] = min(low[u], low[v]);
    			if (dfn[u] < low[v])
    				bri[i] = bri[i ^ 1] = 1;
    		}
    		else if (i != (in_e ^ 1))
    			low[u] = min(low[u], dfn[v]);
    	}
    }
    void dfs(int u, int c)
    {
    	dcc[u] = c;
    	++dcc_num[c];
    	if (!fver[c])
    		fver[c] = u;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v;
    		if (bri[i])
    			continue;
    		if (sel[i] == -1)
    			sel[i] = sel[i ^ 1] = e[i].tp;
    		if (dcc[v] == dcc[u])
    			continue;
    		dfs(v, c);
    	}
    }
    bool vis[N];
    void dfs2(int u)
    {
    	vis[u] = 1;
    	for (int i = head[u]; i; i = e[i].nxt)
    	{
    		int v = e[i].v;
    		if (vis[v])
    			continue;
    		if (bri[i] && sel[i] == -1)
    			sel[i] = sel[i ^ 1] = e[i ^ 1].tp;
    		dfs2(v);
    	}
    }
    int tot;
    void add(int u, int v, int tp)
    {
    	e[++tot].v = v, e[tot].u = u;
    	e[tot].nxt = head[u], head[u] = tot;
    	e[tot].tp = tp;
    }
    int main()
    {
    	memset(sel, -1, sizeof(sel));
    	int u, v;
    	scanf("%d%d", &n, &m);
    	tot = 1;
    	for (int i = 1; i <= m; ++i)
    	{
    		scanf("%d%d", &u, &v);
    		add(u, v, 0);
    		add(v, u, 1);
    	}
    	for (int i = 1; i <= n; ++i)
    		if (!dfn[i])
    			tarjan(i, 0);
    	for (int i = 1; i <= n; ++i)
    		if (!dcc[i])
    			dfs(i, ++dcc_cnt);
    	int maxn = 0, maxpos = 0;
    	for (int i = 1; i <= dcc_cnt; ++i)
    		if (maxn < dcc_num[i])
    			maxn = dcc_num[i], maxpos = i;
    	dfs2(fver[maxpos]);
    	printf("%d
    ", maxn);
    	for (int i = 2; i <= (m << 1) + 1; i += 2)
    	{
    		if (sel[i] == 0)
    			printf("%d %d
    ", e[i].u, e[i].v);
    		else if (sel[i] == 1)
    			printf("%d %d
    ", e[i].v, e[i].u);
    	}
    	return 0;
    }
    

    $*Tarjan$算法牛逼!

  • 相关阅读:
    Android设计中的.9.png图片
    Socket原理
    word2vec中文类似词计算和聚类的使用说明及c语言源代码
    Scala之集合Collection
    使用C语言调用mysql数据库编程实战以及技巧
    Web学习篇之---html基础知识(一)
    μCOS-II系统之事件(event)的使用规则及Semaphore实例
    activiti自己定义流程之Spring整合activiti-modeler实例(一):环境搭建
    将ASP.NET用户控件转化为自定义控件
    【C#】Excel导出合并行和列并动态加载行与列
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/12325302.html
Copyright © 2011-2022 走看看