poj2838 Graph Connectivity 邻接表加上并查集

48 篇文章 0 订阅
32 篇文章 0 订阅
Graph Connectivity
Time Limit: 8000MS Memory Limit: 131072K
Total Submissions: 3381 Accepted: 883
Case Time Limit: 3000MS

Description

Let us consider an  undirected graph G = < V, E >. At first there is no edge in the graph. You are to write a program to calculate the connectivity of two different vertices. Your program should maintain the functions inserting or deleting an edge.

Input

The first line of the input contains an integer numbers N (2 <= N <= 1000) -- the number of vertices in G. The second line contains the number of commands Q (1 <= Q <= 20000). Then the following Q lines describe each command, and there are three kinds of commands: 

I u v: Insert an edge (u, v). And we guarantee that there is no edge between nodes u and v, when you face this command. 
D u v: Delete an existed edge (u, v). And we guarantee that there is an edge between nodes u and v, when you face this command. 
Q u v: A querying command to ask the connectivity between nodes u and v. 

You should notice that the nodes are numbered from 1 to N. 

Output

Output one line for each querying command. Print "Y" if two vertices are connected or print "N" otherwise.

Sample Input

3 
7
Q 1 2
I 1 2
I 2 3
Q 1 3
D 1 2
Q 1 3
Q 1 1

Sample Output

N
Y
N

Y

题意是,给定点数,给出无向边,可以动态的增加删除查询两点是否连通

第一种解法

这里很容易想到图,创建一个邻接表,查询直接用bfs即可,当然dfs也是差不多的,这里给出bfs查询,邻接表,就用vector算了,可以偷偷懒!

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
#define M 1000000
#define N 20005
vector<int> edge[N];
bool vis[N];
queue<int> que;
bool query(int s, int e)
{
	if (s == e)
		return true;
	memset(vis, false, sizeof(vis));
	vis[s] = true;
	while (!que.empty())
	{
		que.pop();
	}
	que.push(s);
	while (!que.empty())
	{
		int k = que.front();
		que.pop();
		vector<int>::iterator it;
		for (it = edge[k].begin(); it != edge[k].end(); it++)
		{
			if (*it == e)
				return true;
			if (!vis[*it])
			{
				que.push(*it);
				vis[*it] = true;
			}
		}
	}
	return false;
}
void inset(int s, int e)
{
	edge[s].push_back(e);
}
void deleteedge(int s, int e)
{
	vector<int>::iterator it;
	int i;
	for (it = edge[s].begin(), i = 0; it != edge[s].end(); it++, i++)
	{
		if (*it == e)
		{
			edge[s].erase(it);
			return;
		}
	}
}
void init()
{
	for (int i = 0; i < N; i++)
	{
		edge[i].clear();
	}
}
int main()
{
	int n, tcase;
	char q;
	int s, e;
	while (scanf("%d", &tcase) != EOF)
	{
		init();
		scanf("%d", &n);
		while (n--)
		{
			getchar();
			q = getchar();
			scanf("%d%d", &s, &e);
			//printf("%c %d %d", q, s, e);
			if (q == 'Q')
			{
				if (query(s, e))
					printf("Y\n");
				else
					printf("N\n");
			}
			else if (q == 'I')
			{
				inset(s, e);
				inset(e, s);
			}
			else if (q == 'D')
			{
				deleteedge(s, e);
				deleteedge(e, s);
			}
		}
	}
	return 0;
}
第二种解法,用并查集加hash表,这里是1000个点,所以可以用hash表,我想要是再大一点就不适用了,用并查集,确实,可以实现,快速查询

两点是否连通,但是如果,删除的话,无疑也是要重建并查集,这点,就很费时间了,看源码

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <algorithm>
#include <iostream>
using namespace std;
#define N 1005
#define M 20005
bool edge[N][N];
int father[N];
void initFather();
int insertFather(int s, int e);
int findfather(int s);
int ncount;
struct node {
	int s, e;
};
node queue[M];
int sum = 0;
void createFather()
{
	initFather();
	for (int i = 0; i < sum;i++)
	{
		if (edge[queue[i].s][queue[i].e])
			insertFather(queue[i].s, queue[i].e);
	}
}
void initFather()
{
	for (int i = 0; i <= ncount; i++)
	{
		father[i] = i;
	}
}
int insertFather(int s, int e)
{
	int x = findfather(s);
	int y = findfather(e);
	if ( x != y)
		father[x] = findfather(y);
	return 0;
}
int findfather(int s)
{
	if (father[s] == s)
		return s;
	else
		return father[s] = findfather(father[s]);
}
bool query(int s, int e)
{
	if (findfather(s) == findfather(e))
		return true;
	else 
		return false;
}
void deleteedge(int s, int e)
{
	edge[s][e] = false;
}
void init()
{
	memset(edge, false, sizeof(edge));
	sum = 0;
	createFather();
}
int main()
{
	int n,tcase;
	char q;
	int s, e;
	while (scanf_s("%d", &tcase) != EOF){
		//while (tcase--)
		{
			ncount = tcase;
			init();
			scanf_s("%d", &n);
			
			while (n--)
			{
				getchar();
				q = getchar();
				scanf_s("%d%d", &s, &e);
				//printf("%c %d %d", q, s, e);
				if (q == 'Q')
				{
					if (query(s, e))
						printf("Y\n");
					else
						printf("N\n");
				}
				else if (q == 'I')
				{
					edge[s][e] = true;
					edge[e][s] = true;
					queue[sum].s = s;
					queue[sum].e = e;
					sum++;
					insertFather(s, e);
				}
				else if (q == 'D')
				{
					deleteedge(s, e);
					deleteedge(e, s);
					createFather();
				}
			}
		}
	}
	return 0;
}


第三种 方法 邻接表加上并查集,这样比上面两种方法,省了时间,也省了内存

#include "stdio.h"
#include "string.h"
#include "math.h"
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
#define N 1005
#define SCANF scanf
vector<int> edge[N];
int ncount;
queue<int> que;
int father[N];
void initFather();
int insertFather(int s, int e);
int findfather(int s);
void createFather()
{
	initFather();
	int i = 0;
	vector<int>::iterator it;
	for (int s = 0; s <= ncount; s++)
	{
		for (it = edge[s].begin(), i = 0; it != edge[s].end(); it++, i++)
		{
			insertFather(s, *it);
		}
	}
}
void initFather()
{
	for (int i = 0; i <= ncount; i++)
	{
		father[i] = i;
	}
}
int insertFather(int s, int e)
{
	int x = findfather(s);
	int y = findfather(e);
	if (x != y)
		father[x] = findfather(y);
	return 0;
}
int findfather(int s)
{
	if (father[s] == s)
		return s;
	else
		return father[s] = findfather(father[s]);
}
bool query(int s, int e)
{
	if (findfather(s) == findfather(e))
		return true;
	else
		return false;
}
void inset(int s, int e)
{
	edge[s].push_back(e);
	insertFather(s, e);
}
void deleteedge(int s, int e)
{
	vector<int>::iterator it;
	int i;
	for (it = edge[s].begin(), i = 0; it != edge[s].end(); it++, i++)
	{
		if (*it == e)
		{
			edge[s].erase(it);
			return;
		}
	}
}
void init()
{
	for (int i = 0; i <= ncount; i++)
	{
		edge[i].clear();
	}
	createFather();
}
int main()
{
	int n, tcase;
	char q;
	int s, e;
	while (SCANF("%d", &tcase) != EOF)
	{
		ncount = tcase;
		init();
		SCANF("%d", &n);
		while (n--)
		{
			getchar();
			q = getchar();
			SCANF("%d%d", &s, &e);
			//printf("%c %d %d", q, s, e);
			if (q == 'Q')
			{
				if (query(s, e))
					printf("Y\n");
				else
					printf("N\n");
			}
			else if (q == 'I')
			{
				inset(s, e);
				inset(e, s);
			}
			else if (q == 'D')
			{
				deleteedge(s, e);
				deleteedge(e, s);
				createFather();
			}
		}
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值