zoj 3509 Island Communication

本文介绍了一种在战争背景下岛屿间通信的算法解决方案。通过维护动态变化的岛屿连接状态,确保商人能够在不确定环境中找到可行路径。
Island Communication

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Once upon a time, human have not invented boats and planes, bridges were the most important things in communication among islands. There is a large kingdom consists of N islands. One day, a terrible war broken out in this country. Due to the war, there might be several bridges being built or destroyed in each day. Tom, one of your best friends, is a business man. People always earn lots of money during the war, and certainly Tom doesn't want to lose this chance. But he doesn't know whether he can get to one island from another island, so he comes to you for help.

Input

There are multiple cases. The first line of each case consists of two integers N and M (1≤N≤500, 1≤M≤50000), indicates the number of islands and the number of operations. The indies of the island are from 1 to N. Then comes M lines of operations. There are three kinds of operations:

  1. I x y: means they build a bridge connects island x and island y
  2. D x y: means they destroy the bridge which connects island x and island y
  3. Q x y: Tom want to know whether he can get to island y from island x

Assume there are no bridges at the beginning, and each bridge will be built at most once(means when one bridge is destroyed, you can never build it any more)

Output

In the first line, you must output the case number. And for each query, you must output "YES" if you can get to island y from island x. otherwise output "NO".

Print a blank line between cases.

Sample Input

5 9
I 1 2
I 2 3
Q 1 3
I 1 3
I 2 4
I 4 5
D 1 2
D 2 3
Q 1 5

Sample Output

Case 1:
YES
NO

分析:

由于点数只有500,其实这题不需要任何高级的数据结构就有一个O(n*m)的算法。注意到点数很少,而要求i和j是否联通,我们只要保留这幅图的生成森林就足够了,即控制边的个数为O(n)。对于查询操作,直接dfs一次即可。对于加边操作,如果i和j不联通,那么直接加上这条边就好了。否则,加上这条边后一定形成一个圈,如果我们把这个圈中最早被删去的边提前删掉,是不会影响后面操作的结果的,所以我们删掉这条边,以保证图中始终没有圈。对于删边操作,如果这个边已经被提前删掉了,那么什么也不做,否则简单删掉就好了。要知道哪条边先被删掉,可以先读入所有操作,预处理之。对于每次操作,复杂度均为O(n),总的复杂度O(n*m)。

由于vector中没有v.erase(key)功能,但这里可用v.ersae(remove(v.begin(),v.end(),key),v.end())代替

代码:

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N=501;
const int M=50000;
vector<int> e[N];
int d[N][N],x[M],y[M],xx,yy,zz;
bool dfs(int p,int s,int t){
	if(s==t)return 1;
	vector<int>::iterator it;
	for(it=e[s].begin();it!=e[s].end();it++){
		if(*it!=p&&dfs(s,*it,t)){
			if(zz>d[s][*it])xx=s,yy=*it,zz=d[xx][yy];return 1;
		}
	}
	return 0;
}
char op[M];
int main(){
	int n,m,i,ca=1;
	while(~scanf("%d%d",&n,&m)){
		for(i=1;i<=n;i++){
			e[i].clear();
			fill(d[i],d[i]+n+1,M);
		}
		for(i=0;i<m;i++){
			scanf(" %c%d%d",&op[i],&x[i],&y[i]);
			if(op[i]=='D')d[x[i]][y[i]]=d[y[i]][x[i]]=i;
		}
		if(ca>1)puts("");
		printf("Case %d:\n",ca++);
		for(i=0;i<m;i++){
			if(op[i]=='I'){
				zz=M;
				if(dfs(-1,x[i],y[i])){
					if(zz<d[x[i]][y[i]]){
					e[xx].erase(remove(e[xx].begin(),e[xx].end(),yy),e[xx].end());
					e[yy].erase(remove(e[yy].begin(),e[yy].end(),xx),e[yy].end());
					e[x[i]].push_back(y[i]);
					e[y[i]].push_back(x[i]);
					}
				}else{
					e[x[i]].push_back(y[i]);
					e[y[i]].push_back(x[i]);
				}
			}
			else if(op[i]=='D'){
				e[x[i]].erase(remove(e[x[i]].begin(),e[x[i]].end(),y[i]),e[x[i]].end());
				e[y[i]].erase(remove(e[y[i]].begin(),e[y[i]].end(),x[i]),e[y[i]].end());
			}
			else puts(dfs(-1,x[i],y[i])?"YES":"NO");
		}
	}
	return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值