poj1703(各种姿势)
题目链接:http://poj.org/problem?id=1703
题意:有n个人分别属于两个团伙,接下来m组形如 ch, x, y的数据,ch为“D"表示 x, y属于不同的团伙,ch为"A"表示询问x,y书否属于同一个团伙;
解法1:我们可以用jion(x, y)属于同一个团伙,jion(x+n, y)表示x属于第二个团伙,y属于第一个团伙,jion(x, y+n)表示x属于第一个团伙,y属于第二个团伙;
那么对于每组不同团伙的x, y我们只需要jion(x+n, y) ,jion(x, y+n)即可;查询时判断x,y或者x+n, y+n根节点是否相同即可,因为集合关系jion表示属于同一团伙,根节点相同则属于相同团伙,若x, y+n,或者x+n, y根节点相同则属于不同团伙,其余情况即为不能确定;
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN (100000+10) //***MAXN后面做下标时MAXN*2,要加括号,不然会越界!!run time error!!!
using namespace std; int pre[MAXN*], rank[MAXN*]; //***rank用来区分树的高度,但其不存储树的具体高度 int find(int x){
int r = x;
while(pre[r]!=r){
r = pre[r];
}
int i = x; //****路径压缩
while(pre[i]!=r){
int gg = pre[i];
pre[i] = r;
i = gg;
}
return r;
} void jion(int x, int y){
int xx = find(x);
int yy = find(y);
if(rank[xx]>rank[yy]){ //***启发式合并,就是把矮的树合并到高的树地下,把合并时间从0(n)降到o(logn)
pre[yy] = xx;
}else{
pre[xx] = yy;
if(rank[xx] == rank[yy]){ //**若树的标记高度一样,那么给合并后作为父亲的树rank+1,以区分树的高度
rank[xx]++;
}
}
} int main(void){
int t;
scanf("%d", &t);
while(t--){
int n, m;
scanf("%d%d", &n, &m);
for(int i=; i<=*n; i++){
pre[i] = i;
rank[i] = ;
}
while(m--){
char ch[];
int x, y;
scanf("%s%d%d", ch, &x, &y);
if(ch[]=='D'){
jion(x, y+n);
jion(x+n, y);
}else{
if(find(y+n)==find(x)||find(x+n)==find(y)){
printf("In different gangs.\n");
}else if(find(x)==find(y)||find(x+n)==find(y+n)){
printf("In the same gang.\n");
}else{
printf("Not sure yet.\n");
}
}
}
}
return ;
}
方法2:用vis数组标记不同的集合,如:vis[x]=y,表示与x不同集合的点y;
用并查集合并属于同一类的点集;
代码:
#include <iostream>
#include <stdio.h>
#define MAXN 100010
using namespace std; int pre[MAXN], vis[MAXN], rank[MAXN]; //***vis标记不同集合的编号,rank区分树高
//***vis[x]=y,表示记录x与y不同集合,相当于无向图,所以需双向标记 /*int find(int x){ //**400+ms
int r = x;
while(pre[r]!=r){
r = pre[r];
}
int i = x;
while(i!=r){
int gg = pre[i];
pre[i] = r;
i = gg;
}
return r;
}*/ int find(int x){ //**306ms (再加启发式合并=282ms)
return pre[x]==x ? x : pre[x] = find(pre[x]);
} void jion(int x, int y){
int xx = find(x);
int yy = find(y);
if(rank[xx] > rank[yy]){
pre[yy] = xx;
}else{
pre[xx] = yy;
if(rank[xx] == rank[yy]){
rank[yy]++;
}
}
} int main(void){
int t;
scanf("%d", &t);
while(t--){
int n, m;
scanf("%d%d", &n, &m);
for(int i=; i<=n; i++){
pre[i] = i;
vis[i] = ;
rank[i] = ;
}
while(m--){
char ch[];
int x, y;
scanf("%s%d%d", ch, &x, &y);
if(ch[]=='D'){
if(vis[x]== && vis[y]==){ //**x, y都没出现过
vis[x] = y;
vis[y] = x;
}else if(vis[x]==){ //**x没出现过
vis[x] = y;
jion(x, vis[y]);
}else if(vis[y]==){ //**y没出现过
vis[y] = x;
jion(y, vis[x]);
}else{ //**都出现过
jion(x, vis[y]);
jion(y, vis[x]);
}
}else{
if(find(x)==find(y)){
printf("In the same gang.\n");
}else if(find(x)==find(vis[y])){
printf("In different gangs.\n");
}else{
printf("Not sure yet.\n");
}
}
}
}
return ;
}
方法3:
种类并查集,先区分能不能辨别的情况,然后只要考虑同和不同两种情况,可以用rank数组记录当前节点x与其根节点是否相同的信息,1表相同,0表不同;
代码:
#include <iostream>
#include <stdio.h>
#define MAXN 100010
using namespace std; int pre[MAXN], rank[MAXN]; //**rank储存x与x的根节点是否相同的信息,1表相同,0表不同 int find(int x){
if(x==pre[x]){
return pre[x];
}
int xx = pre[x];
pre[x] = find(pre[x]);
rank[x] = (rank[x] + rank[xx])&; //**压缩路径,x的根节点改变了,rank[x]也要改变
return pre[x];
} void jion(int x, int y){
int xx = find(x);
int yy = find(y);
if(xx!=yy){
pre[yy] = xx;
rank[yy] = (rank[x] + rank[y] + )&; //**合并只需改变yy之前的rank值
}
} int main(void){
int t;
scanf("%d", &t);
while(t--){
int n, m;
scanf("%d%d", &n, &m);
for(int i=; i<=n; i++){
pre[i] = i;
rank[i] = ;
}
while(m--){
char ch[];
int x, y;
scanf("%s%d%d", ch, &x, &y);
if(ch[]=='D'){
jion(x, y);
}else{
if(find(x)==find(y)){
if(rank[x]==rank[y]){
printf("In the same gang.\n");
}else{
printf("In different gangs.\n");
}
}else{
printf("Not sure yet.\n");
}
}
}
}
return ;
}
poj1703(各种姿势)的更多相关文章
- 内网劫持渗透新姿势:MITMf简要指南
声明:本文具有一定攻击性,仅作为技术交流和安全教学之用,不要用在除了搭建环境之外的环境. 0×01 题记 又是一年十月一,想到小伙伴们都纷纷出门旅游,皆有美酒佳人相伴,想到这里,不禁潸然泪下.子曰:& ...
- 判断是否为gif/png图片的正确姿势
判断是否为gif/png图片的正确姿势 1.在能取到图片后缀的前提下 1 2 3 4 5 6 7 8 9 //假设这是一个网络获取的URL NSString *path = @"http:/ ...
- 在Linux(ubuntu server)上面安装NodeJS的正确姿势
上一篇文章,我介绍了 在Windows中安装NodeJS的正确姿势,这一篇,我们继续来看一下在Linux上面安装和配置NodeJS. 为了保持一致,这里也列举三个方法 第一个方法:通过官网下载安装 h ...
- 聊聊 Web 项目二维码生成的最佳姿势
在设计和实现的过程之后,你永远不知道部署上去的程序会已什么样的姿势运行. 本篇借一次生成二维码逻辑的不同实现,阐述 Web 项目中二维码生成的正确姿势. 文中如有批量,欢迎各位看客老爷拍砖.试运行前5 ...
- Lua手动编译姿势
LUA-5.3.3.tar.gz Lua源码+链接2016年5月30日更新 手动编译姿势: 已经装有VS2010 使用VS自带的 cl.exe以及 VS命令簿 打开文件地址 运行自己的bat文件 my ...
- 浅谈OC对象初始化的三种姿势
一.普通程序猿普通程序员使用最常见路人姿势等场.普普通通,纯属陆仁辈. 陆仁贾写法: // view 1 UIView *v1 = [UIView alloc] initWithFrame:CGRec ...
- 与MySQL传统复制相比,GTID有哪些独特的复制姿势?
与MySQL传统复制相比,GTID有哪些独特的复制姿势? http://mp.weixin.qq.com/s/IF1Pld-wGW0q2NiBjMXwfg 陈华军,苏宁云商IT总部资深技术经理,从事数 ...
- 快速了解IOC的几种姿势
一.首先我们了解IOC如何注入的几种姿势 构造函数注入(Constructor Injection) Ioc容器会智能的选择和调用合适的构造函数以创建依赖的对象.如果被选择的构造函数具有相应的参数,I ...
- xpath轴的正确使用姿势
网上看了许多关于轴的介绍,只介绍了语法,而没有明说具体实际中该怎么使用,百思不得其解. 背景--python中使用xpath: ----------------------------------- ...
随机推荐
- java之String
一.构造器 package com.string; import java.io.UnsupportedEncodingException; import java.nio.charset.Chars ...
- linux下用Apache一个IP多个域名建虚拟主机
如有两个域名,分别是hello.abc.com和play.abc.com,需把这两个域名都绑定到 IP是219.13.34.32的服务器上 1.首先需在域名供应商管理页面指定域名和IP的对应关系 2. ...
- nginx命令
window cmd 到nginx的文件夹 start nginx 启动命令 nginx -s reload 重新启动 nginx -s stop 关闭 linux 到 sbin ...
- mysql 设置可以外部访问
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%' IDENTIFIED BY 'mypassword' WITH GRANT OPTION; --授权可以外部 ...
- CSU 1113 Updating a Dictionary(map容器应用)
题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1113 解题报告:输入两个字符串,第一个是原来的字典,第二个是新字典,字典中的元素的格式为 ...
- web安全及防护
本文将对web方面的安全问题以及相应的防护方法进行一个简单的介绍. SQL注入(SQL Injection) 原理:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺 ...
- javascript 常用技巧
1. 将彻底屏蔽鼠标右键 oncontextmenu=”window.event.returnValue=false” < table border oncontextmenu=return(f ...
- Objective C 快速入门学习二
Objective-C 类.对象.方法 1.编写一个复数类: #import <Foundation/Foundation.h>@interface Complex: NSObject / ...
- ModelState.IsValid
model内的设置如下所示: /// <summary> /// 取得或设置邮编 /// </summary> [RegularExpression(@"(^[1-9 ...
- Nodejs 及 NPM 的安装
Nodejs 及 NPM 的安装,有两种方式: 方式1.Nodejs 及 NPM 一起安装 https://nodejs.org/en/download/ 下载 Windows Installe ...