Codeforces 104C Cthulhu dfs暴力 || 双连通缩点

题目链接:点击打开链接

题意:

给定n个点m条边的无向图

问图中是否存在 有且仅有一个简单环和一些树,且这些树的root都在这个简单环上。

瞎写了个点双。。==

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
#include <set>
using namespace std;
#define N 105
#define M 100005
#define inf 10000000
struct Edge{
	int from,to,next;
}edge[2*M];
int head[N],edgenum;
int Low[N],DFN[N],Stack[N];//Belong数组的值是1~block
int Index,top;
int Belong[N],block;//新图的连通块标号(1~block)
bool Instack[N];
int bridge; //割桥数量
vector<int> bcc[N];
void addedge(int u,int v){
	Edge E={u,v,head[u]}; edge[edgenum]=E; head[u] = edgenum++;
	Edge E2={v,u,head[v]};edge[edgenum]=E2;head[v] = edgenum++;
}
void Tarjan(int u,int pre){
	int v;
	Low[u] = DFN[u] = ++Index;
	Stack[top++] = u;
	Instack[u] = true;
	for(int i = head[u]; ~i ;i = edge[i].next){
		v = edge[i].to;
		// 如果重边有效的话下面这句改成: if(v == pre && pre_num == 0){pre_num++;continue;} pre_num在for上面定义 int pre_num=0;
		if( v == pre )continue;
		if( !DFN[v] ){
			Tarjan(v,u);
			if(Low[u] > Low[v])Low[u] = Low[v];
			if(Low[v] > Low[u])
				bridge++;
		}
		else if(Instack[v] && Low[u] > DFN[v])Low[u] = DFN[v];
	}
	if(Low[u] == DFN[u]){
		block++;
		bcc[block].clear();
		do{
			v = Stack[--top];
			Instack[v] = false;
			Belong[v] = block;
			bcc[block].push_back(v);
		}while( v != u );
	}
}
void work(int l, int r){
	memset(DFN,0,sizeof(DFN));
	memset(Instack,false,sizeof(Instack));
	Index = top = block = bridge = 0;
	for(int i = l; i <= r; i++)if(!DFN[i])Tarjan(i,i);
}
vector<int>G[N];
void suodian(){
	for(int i = 1; i <= block; i++)G[i].clear();
	for(int i = 0; i < edgenum; i+=2){
		int u = Belong[edge[i].from], v = Belong[edge[i].to];
		if(u==v)continue;
		G[u].push_back(v), G[v].push_back(u);
	}
}
void init(){edgenum = 0; memset(head,-1,sizeof(head));}

int n, m, vis[N], siz[N], f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void Union(int x, int y){
    int fx = find(x), fy = find(y);
    if(fx==fy)return;
    if(fx>fy)swap(fx,fy); f[fx] = fy;
}
bool dfs(int u){
	vis[u] = 1;
	bool ok = true;
	for(int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i]; if(vis[v])continue;
		if(bcc[v].size()>1)ok = false;
		if(dfs(v)==false)ok = false;
	}
	return ok;
}
set<int>myset;
bool solve(){
	int i, u, v;
	init();
	for(i = 1; i <= n; i++)f[i] = i;
	while(m--){
		scanf("%d %d",&u,&v);
		addedge(u, v);
		Union(u,v);
	}
	myset.clear();
	for(i = 1; i<= n; i++)myset.insert(find(i));
	if(myset.size()>1)return false;
	work(1, n);
	suodian();
	memset(vis, 0, sizeof vis);
	memset(siz, 0, sizeof siz);
	for(i = 0; i < edgenum; i+=2)
		siz[u]+= (Belong[edge[i].from]==Belong[edge[i].to]);

	for(i = 1; i <= block; i++) if(!vis[i] && bcc[i].size()>1 && bcc[i].size()==siz[i] && G[i].size()>=3)
		if(dfs(i))return true;

	return false;
}
int main(){
	while(~scanf("%d %d", &n, &m))
		solve() ? puts("FHTAGN!") : puts("NO");
	return 0;
}
/*
6 6
1 2
2 3
3 1
4 5
5 6
6 4

*/
时间: 2024-10-06 05:38:41

Codeforces 104C Cthulhu dfs暴力 || 双连通缩点的相关文章

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

poj3694--Network(双连通缩点+lca)

poj3694:题目链接 题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量 首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少. 图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了 #include <cstdio> #include <cstring> #include <algorithm> #include &l

poj 2942 Knights of the Round Table 【双连通缩点+判奇圈】【经典】

题目:poj 2942 Knights of the Round Table 题意:n个骑士经常一起开会,其中有一些两两相互憎恨,他们不能同一桌,开会要表决一些事情,所以必须奇数个人,最少3个,求永远也参加不了会议的人的个数. 分析:这个题目两点 首先,建图求双连通缩点 建图的话,因为相互憎恨的不能再一块,所以要建补图,让能够在一起的所有的连接,这样的话,如果能存在环且环上的点是奇数个的话就可以参加会议,标记求不能参加的即可. 建好图之后用tarjan算法双连通缩点,把在一个环上的点保存起来.

HDU 5409 CRB and Graph 双连通缩点 + st表

HDU 5409 显然要先双连通缩成一棵树. 然后对于树上的边才有答案. 对于一条边来说, 两侧的最大值分为mx1 , mx2 , 那么 u 一定是min(mx1, mx2), v 一定是 u + 1. 这个经过仔细分析一下就能得到, 然后按dfs序建个st表就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi firs

【连通图|边双连通+缩点】POJ-3177 Redundant Paths

Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K       Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the T

【连通图|边双连通+缩点】POJ-3352 Road Construction

Road Construction Time Limit: 2000MS Memory Limit: 65536K Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the roads on the tropical island paradise of Remo

poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&amp;&amp;缩点】

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10141   Accepted: 5031 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the r

hdu4612(双连通缩点+树的直径)

传送门:Warm up 题意:询问如何加一条边,使得剩下的桥的数目最少,输出数目. 分析:tarjan缩点后,重新建图得到一棵树,树上所有边都为桥,那么找出树的直径两个端点连上,必定减少的桥数量最多,因此ans=树的边数-树的直径. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <string>

HDU 4005 The war(双连通好题)

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