Light OJ 1291 Real Life Traffic 双连通最少添边数

题目来源:Light OJ 1291 Real Life Traffic

题意:最少添加几条边 可以使全图边双连通

思路:缩点 重新构图 答案就是(叶子节点数+1)/ 2

#include <vector>
#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn = 10010;
struct Edge
{
	int u, v;
	Edge(){}
	Edge(int u, int v): u(u), v(v){}
};
vector <int> a[maxn];
int pre[maxn];
int low[maxn];
int bccno[maxn];
int dfs_clock;
int bcc_cnt;
int bri;
int n, m;
int degree[maxn];
stack <int> S;

void dfs(int u, int fa)
{
	low[u] = pre[u] = ++dfs_clock;
	S.push(u);
	for(int i = 0; i < a[u].size(); i++)
	{
		int v = a[u][i];
		if(v == fa)
			continue;
		if(!pre[v])
		{
			dfs(v, u);
			low[u] = min(low[u], low[v]);
		}
		else if(v != fa)
			low[u] = min(low[u], pre[v]);
	}
	if(low[u] == pre[u])
	{
		bcc_cnt++;
		while(1)
		{
			int x = S.top(); S.pop();
			bccno[x] = bcc_cnt;
			if(x == u)
				break;
		}
	}
}
void find_bcc()
{
	memset(pre, 0, sizeof(pre));
	memset(bccno, 0, sizeof(bccno));
	dfs_clock = bcc_cnt = bri = 0;
	for(int i = 0; i < n; i++)
		if(!pre[i])
			dfs(i, -1);
}
int main()
{
	int cas = 1;
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d", &n, &m);
		for(int i = 0; i <= n; i++)
			a[i].clear();
		while(m--)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			a[u].push_back(v);
			a[v].push_back(u);
		}

		find_bcc();
		memset(degree, 0, sizeof(degree));
		for(int u = 0; u < n; u++)
		{
			for(int i = 0; i < a[u].size(); i++)
			{
				int v = a[u][i];
				if(bccno[u] != bccno[v])
				{
					degree[bccno[u]]++;
					degree[bccno[v]]++;
				}
			}
		}
		int ans = 0;
		for(int i = 1; i <= bcc_cnt; i++)
			if(degree[i] == 2)
				ans++;
		printf("Case %d: %d\n", cas++, (ans+1)/2);
	}
	return 0;
}

Light OJ 1291 Real Life Traffic 双连通最少添边数

时间: 2024-11-08 07:09:16

Light OJ 1291 Real Life Traffic 双连通最少添边数的相关文章

Light OJ 1258 Making Huge Palindromes 末尾添加最少字符变回文串

题目来源:Light OJ 1258 Making Huge Palindromes 题意:末尾添加最少的字符是使输入的串变成回文 输出长度 思路:直接KMP匹配出它和它反串的最大匹配 n减去它就是要添加的数量 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000010; char a[maxn], p[maxn]; int

POJ3352 Road Construction Tarjan+边双连通

题目链接:http://poj.org/problem?id=3352 题目要求求出无向图中最少需要多少边能够使得该图边双连通. 在图G中,如果任意两个点之间有两条边不重复的路径,称为“边双连通”,去掉任何一条边都是其他边仍然是连通的,也就是说边双连通图中没有割边. 算法设计是:运用tarjan+缩点.对于每一个边双连通分量,我们都可以把它视作一个点,因为low值相同的点处在同一个边双连通分量中,可以简单地思考一下,(u,v)之间有两条可达的路径,dfs一定可以从一条路开始搜索并且从另一条路回去

LightOJ 1291 Real Life Traffic

Real Life Traffic Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged on LightOJ. Original ID: 129164-bit integer IO format: %lld      Java class name: Main Dhaka city is full of traffic jam and when it rains, some of the roads becom

【图论】双连通总结

双连通总结 这类问题分为,边-双连通,点-双连通 边双连通 边双连通,求出来后,连接没一个双连通的分量的就是割边,因此可以缩点成一棵树,把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通 基本这类题都一个解法,求双连通分量,然后缩点成树,进行操作 或者就是直接要求割边,做跟割边相关的操作 模板: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #

light oj 1236 【大数分解】

给定一个大数,分解质因数,每个质因子的个数为e1,e2,e3,--em, 则结果为((1+2*e1)*(1+2*e2)--(1+2*em)+1)/2. //light oj 1236 大数分解素因子 #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> #include <ctype.h> #i

[2016-04-21][light]OJ[1234][Harmonic Number]

时间:2016-04-21 22:18:26 星期四 题目编号:[2016-04-21][light]OJ[1234][Harmonic Number] 题目大意:求∑nk=11kn∈(1,108),精确到10?8求∑k=1n1kn∈(1,108),精确到10?8 分析: 想法是打表,然后输出,但是直接打表会爆内存 解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值 对应的整百就是n

HDU 4005 The war(双连通好题)

HDU 4005 The war 题目链接 题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通 思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可 代码:

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

ACM学习-图双连通子图

// ACM学习-割点和桥.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<queue> #include<vector> #include<algorithm> using namespace std; const int v = 13; int edge[v][v] = { { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0