A : Wireless Network  POJ - 2236

题意:并查集,可以有查询和修复操作

题解:并查集

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define N 1110
int d;
bool use[N]; struct node
{
int pre;
int x, y;
}p[N]; int find(int x)
{
return x == p[x].pre ? x : find(p[x].pre);
} void join(const node p1, const node p2)
{
int root1, root2;
root1 = find(p1.pre);
root2 = find(p2.pre);
if(root1 != root2)
if((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) <= d * d)
p[root2].pre = root1;
} int main()
{
//freopen("Input.txt", "r", stdin);
int num;
char ope;
int ok;
int from, to;
scanf("%d%d", &num, &d);
for(int i = ; i <= num; ++i)
p[i].pre = i;
memset(use, false, sizeof(use));
for(int i = ; i <= num; ++i)
scanf("%d%d", &p[i].x, &p[i].y);
while(scanf("\n%c", &ope) != EOF)
{
if(ope == 'O')
{
scanf("%d", &ok);
use[ok] = true;
for(int i = ; i <= num; ++i)
if(use[i] && i != ok)
join(p[i], p[ok]);
}
else
{
scanf("%d%d", &from, &to);
if(find(from) == find(to))
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
return ;
}

B:The Suspects POJ - 1611

题意:0节点为携带病毒人,有一些团队,一个人可以在多个团队,一个团队一个有病毒,其余都感染,问一共几人感染病毒

题解:寻找0号根结点对应的sum值

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn = 1e5+;
const int mod = 1e9+; int father[maxn],sum[maxn];
void init(int n)
{
for(int i=;i<n;i++)
{
father[i] = i;
sum[i] = ;
}
}
int find(int x)
{
if(father[x] == x)
return x;
else
return father[x] = find(father[x]);
}
void combine(int x,int y)
{
int xx = find(x);
int yy = find(y);
if(xx != yy) {
father[xx] = yy;
sum[yy] += sum[xx];
}
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
init(n);
if(n == && m == )
break;
for(int i=;i<m;i++)
{
int x;
scanf("%d",&x);
int one,two;
scanf("%d",&one);
for(int j=;j<x;j++)
{
scanf("%d",&two);
combine(one,two);
}
}
printf("%d\n",sum[find()]);
}
}

C:How Many Tables  hdu-1213

题意:认识的人可以坐在一张桌子,也可以间接认识,问需要几张桌子

思路:并查集之后找有几个集

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<map>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3+; int father[maxn];
void init(int n)
{
for(int i=;i<=n;i++)
father[i] = i;
}
int find(int x)
{
if(father[x] == x)
return x;
else
return father[x] = find(father[x]);
}
void combine(int x,int y)
{
x = find(x);
y = find(y);
if(x != y)
father[x] = y;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d %d", &n,&m);
init(n);
for(int i=;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
combine(a,b);
}
int res = ;
for(int i=;i<=n;i++)
if(i == find(i))
res++;
printf("%d\n",res);
}
}

D:How Many Answers Are Wrong  hdu-3038

题意:现在有n个数(你并不知道这n个数是什么),m次查询,每次查询给出u,v,w。表示从第u个数到第v个数的和为w。
   问,在这些查询中,有多少个是错误的(即有冲突)。

思路:带权并查集

从第u个数到第v个数的和其实可以理解为,第u-1个数到v个数之间的和。那么,就可以把和当成一种关系,利用带权并查集来维护这种关系。u-1节点为根,v的权值为第u-1个数到v个数之间的和。这里需要理解一下的是,在Find函数和unite(合并)函数里面,有两个关系域的转移方程(暂且这么叫他吧)
①p[x].relation+=p[tmp].relation
②p[root2].relation=p[x].relation+relation-p[y].relation

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<map>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5+;
struct node
{
int father;
int w;
};
node p[maxn];
int n,m,ans;
void init()
{
ans = ;
for(int i=;i<=n;i++)
{
p[i].father = i;
p[i].w = ;
}
} int find(int x)
{
if(x == p[x].father)
return x;
int tmp = p[x].father;
p[x].father = find(tmp);
p[x].w += p[tmp].w;
return p[x].father;
} void combine(int x,int y,int w)
{
int x1 = find(x);
int y1 = find(y);
if(x1 != y1)
{
p[y1].father = x1;
p[y1].w = p[x].w + w -p[y].w;
}
else
{
if(p[y].w - p[x].w != w)
ans ++;
}
} int main()
{
while(~scanf("%d %d",&n,&m))
{
int u,v,w;
init();
for(int i=;i<m;i++)
{
scanf("%d %d %d",&u,&v,&w);
u -= ;
combine(u,v,w);
}
printf("%d\n",ans);
}
}

E - 食物链 POJ - 1182

题意:A吃B,B吃C,C吃A,给出一些话,问有几句假话

题解:可开3倍数组,也可以用结构体,关系域用向量加减操作

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<map>
#include<cstdlib>
#include<vector>
#include<string>
#include<queue>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
const double PI = acos(-1.0);
const int maxn = 5e4+;
const int mod = 1e9+; struct node
{
int pre;
int relation; //0:与根节点同类 1:被根节点吃 2:吃根节点
}p[maxn]; int find(int x)
{
int temp;
if(x == p[x].pre)
return x;
temp = p[x].pre;
p[x].pre = find(temp);
p[x].relation = (p[x].relation + p[temp].relation) % ;
return p[x].pre;
}
int main()
{
int n,k;
int ope,a,b;
int root1,root2;
int sum = ;
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
{
p[i].pre = i;
p[i].relation = ;
}
while(k--)
{
scanf("%d%d%d",&ope,&a,&b);
if(max(a,b) > n)
{
sum++;
continue;
}
if(ope == && a == b)
{
sum++;
continue;
}
root1 = find(a);
root2 = find(b);
if(root1 != root2)
{
p[root2].pre = root1;
p[root2].relation = (+(ope - ) + p[a].relation - p[b].relation) % ;
}
else
{
if(ope == &&p[a].relation != p[b].relation)
{
sum++;
continue;
}
if(ope == &&(( - p[a].relation + p[b].relation) % != ope -))
{
sum++;
continue;
}
}
}
printf("%d\n",sum);
}

F - True Liars POJ - 1417

题目大意:给你p1个好人和p2个坏人,编号为1-p1+p2,然后给你n中操作

x1 x2 no:x1说x2不是好人

x1 x2 yes:x1说x2是好人

在这里好人说的总是对的,坏人说的总是坏的,然后问你最后能不能唯一确定哪些是好人,并输出不能就输出no

题目思路:开始看到这题很好想到的就是用并查集,如果是yes的话说明他们同类,no的话说明不是同类,但这样只能分出几个大集合来,每个集合又分成两个小集合表示两种类型的个数,而我们要求的是在所有大集合中选出一个小集合然后加起来看能不能组 合成p1,并且要唯一,这里我们可以想到用背包来做,dp[i][j]表示前i个大集合好人为j个的方案数,第i种状态只能是有第i-1种状态而来,我们用w0[i],w1[i]表示第i个集合两个小集合的个数 ,所以dp[i][j]可以由dp[i-1][j-w0[]i]和dp[i-1][j-w1[i]]得来,这样我们只需判断dp[cnt][p1]是否等于1,这题还有麻烦的就是输出好人的编号,这里我们可以利用边的权值,w0存的全是权值为0的w1存的全是权值为1的,然后最后只需判断下第i个集合是由w0还是w1组合而来,这里可以利用dp[i-1][p1-w0[i]]的值来判断,如果等于1则表示是由w0组合否则就是w1,这个不难理,dp[i-1][p1-w0[i]]==1可以得到dp[i][p1]==1,应为这里已经表示答案唯一,所以只有一种情况!

此题题意题解转载自:  https://blog.csdn.net/qq_34731703/article/details/54603652

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include <set>
#include<queue>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn = 1e3+;
const ll mod = 1e9+; int pre[maxn],rk[maxn],p[maxn],vis[maxn];
int w0[maxn],w1[maxn],dp[maxn][maxn];
int n,p1,p2;
void init()
{
for(int i=;i<=p1+p2;i++)
{
pre[i] = i;
rk[i] = ;
vis[i] = ;
w0[i] = w1[i] = ;
}
memset(dp,,sizeof dp);
}
int find(int x)
{
if(x != pre[x])
{
int temp = pre[x];
pre[x] = find(pre[x]);
rk[x] = rk[x] ^ rk[temp];
}
return pre[x];
}
void combine(int x,int y,int k)
{
int xx = find(x);
int yy = find(y);
if(xx != yy)
{
pre[xx] = yy;
rk[xx] = rk[x] ^ rk[y] ^ k;
}
}
int main()
{
while(scanf("%d %d %d",&n,&p1,&p2) && (n + p1 + p2))
{
init();
for(int i=;i<n;i++)
{
int a,b;
char str[];
scanf("%d %d %s",&a,&b,str);
if(str[] == 'y')
combine(a,b,);
else
combine(a,b,);
}
int cnt = ;
for(int i=;i<=p1+p2;i++)
{
if(!vis[i])
{
int fa = find(i);
for(int j=i;j<=p1+p2;j++)
{
if(find(j) == fa && !vis[j])
{
vis[j] = ;
if(rk[j] == )
w0[cnt]++;
else
w1[cnt]++;
}
}
p[cnt] = fa;
cnt++;
}
}
dp[][] = ;
for(int i=;i<cnt;i++)
{
int minn = min(w0[i],w1[i]);
for(int j=p1;j>=minn;j--)
{
if(dp[i-][j-w0[i]])
dp[i][j] += dp[i-][j-w0[i]];
if(dp[i-][j-w1[i]])
dp[i][j] += dp[i-][j-w1[i]];
}
} if(dp[cnt-][p1] != )
{
puts("no");
continue;
}
int ans[maxn];
int num = ;
int good = p1;
for(int i=cnt-;i>=;i--)
{
if(dp[i-][good-w0[i]] == )
{
for(int j=;j<=p1+p2;j++)
if(find(j) == p[i] && rk[j] == )
ans[num++]=j;
good -= w0[i];
}
else
{
for(int j=;j<=p1+p2;j++)
if(find(j) == p[i] && rk[j] == )
ans[num++] = j;
good -= w1[i];
}
}
sort(ans,ans + num);
for(int i=;i<num;i++)
printf("%d\n",ans[i]);
puts("end");
}
return ;
}

G - Supermarket POJ - 1456

题意:超市里有n个产品要卖,每个产品都有一个截至时间d(从开始卖时算起),只有在这个截至时间之前才能卖出并且获得率润dy。

题解:先将产品按照价格从高到低排序,之后用并查集来寻找还有的时间

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include <set>
#include<queue>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn = 1e4+;
const ll mod = 1e9+;
struct node
{
int p,d;
}a[maxn];
int pre[maxn];
bool cmp(node a,node b)
{
return a.p > b.p;
}
int find(int x)
{
if(pre[x] == -)
return x;
else
return pre[x] = find(pre[x]);
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(pre,-,sizeof pre);
for (int i = ; i < n; i++)
scanf("%d %d",&a[i].p,&a[i].d);
sort(a,a+n,cmp);
int ans = ;
for(int i=;i<n;i++)
{
int t = find(a[i].d);
// cout<<t<<endl;
if(t)
{
ans += a[i].p;
pre[t] = t-;
//cout<<"pre[t]"<<t-1<<endl;
}
}
printf("%d\n",ans);
}
return ;
}

M - 小希的迷宫 HDU - 1272

题意:给一张地图,要求任意的两个房间之间只有一条路,是的输出Yes,不是的输出No

思路:使用并查集,当发现两个房间的根节点不一样的话就将两个房间连接起来,如果两个房间的根节点是一样的话,说明成环了,就不是。同时,也有可能不是联通的,需要验证,就是只有一个根节点在所有的点中,还有一个特判,直接输入0 0 的话输出的是Yes

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include <set>
#include<queue>
#include<map>
using namespace std; #define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn = 1e5+;
const ll mod = 1e9+;
const double eps = 1e-; int pre[maxn];
int vis[maxn]; void init()
{
for(int i=;i<maxn;i++)
pre[i] = i;
memset(vis,,sizeof vis);
}
int find(int x)
{
if(x == pre[x])
return x;
else
return pre[x] = find(pre[x]);
} void combine(int x,int y)
{
int fx = find(x);
int fy = find(y);
if(fx != fy)
pre[fy] = fx;
}
bool same(int x,int y)
{
int fx = find(x);
int fy = find(y);
return fx == fy;
}
int main()
{
int a,b;
while(scanf("%d%d",&a,&b))
{
init();
vis[a] = vis[b] = ;
if(a == - && b == -)
break;
if(a== && b==)
{
puts("Yes");
continue;
}
combine(a,b);
int x,y;
int flag = ;
while(scanf("%d%d",&x,&y))
{
if(x== && y==)
{
int ans = ;
for(int i=;i<maxn;i++)
if(vis[i] && pre[i]==i) {
ans++;
//cout<<i<<endl;
}
if(flag == && ans == )
puts("Yes");
else
puts("No");
break;
}
vis[x] = vis[y] = ;
if(!same(x,y))
combine(x,y);
else
flag = ;
}
}
}

kuangbin 并查集的更多相关文章

  1. [ An Ac a Day ^_^ ] [kuangbin带你飞]专题五 并查集 POJ 2236 Wireless Network

    题意: 一次地震震坏了所有网点 现在开始修复它们 有N个点 距离为d的网点可以进行通信 O p   代表p点已经修复 S p q 代表询问p q之间是否能够通信 思路: 基础并查集 每次修复一个点重新 ...

  2. kuangbin带你飞 并查集 题解

    做这套题之前一直以为并查集是很简单的数据结构. 做了才发现自己理解太不深刻.只看重片面的合并集合.. 重要的时发现每个集合的点与这个根的关系,这个关系可以做太多事情了. 题解: POJ 2236 Wi ...

  3. [kuangbin带你飞]专题五 并查集

    并查集的介绍可以看下https://www.cnblogs.com/jkzr/p/10290488.html A - Wireless Network POJ - 2236 An earthquake ...

  4. kuangbin带我飞QAQ 并查集

    1. POJ 2236 给出N个点,一开始图是空白的,两个操作,一个是增加一个点(给出坐标),一个是查询两个点间是否相通,当两点间的距离小于D或者两点通过其他点间接相连时说这两个点相通.并查集维护,每 ...

  5. POJ 1417 True Liars(种类并查集+dp背包问题)

    题目大意: 一共有p1+p2个人,分成两组,一组p1,一组p2.给出N个条件,格式如下: x y yes表示x和y分到同一组,即同是好人或者同是坏人. x y no表示x和y分到不同组,一个为好人,一 ...

  6. HDU 4750 Count The Pairs (2013南京网络赛1003题,并查集)

    Count The Pairs Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others ...

  7. poj2513连接木棍(字典树+欧拉回路+并查集)

    题目传送门 题目大意:给你一堆木棍,每根木管都有两种颜色,相同颜色的部分可以连接起来,问你这堆木棍可不可以连接成1根. 思路:大致的思路很好想,就是判断欧拉回路的方法(1.联通,2,要么顶点读书全为偶 ...

  8. POJ-2153Colored Sticks解题报告+欧拉回路,字典树,并查集;

    传送门:http://poj.org/problem?id=2513 题意:给你许多木棍,木棍两端都有颜色,问能不能首尾相接,要求颜色相同. 参考:https://www.cnblogs.com/ku ...

  9. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

随机推荐

  1. Java获取系统信息(用户目录,临时目录等)

    java.version Java运行时环境版本 java.vendor Java运行时环境供应商 java.vendor.url Java供应商的 URL java.home Java安装目录 ja ...

  2. pat1083. List Grades (25)

    1083. List Grades (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given a l ...

  3. MySQL导入大sql 文件大小限制问题的解决

    解决过程如下: 1.由于mysql能解析sql的压缩文件,因此将200M压缩后为5M. 2.默认情况下:MySQL导入文件大小有限制的,最大为2M,所以当文件很大时候,直接无法导入,可修改php.in ...

  4. 打印流-PrintStream

    打印流-PrintStream java.io.PrintStream为其他输出流添加了功能,使其他的流能够更方便的打印各种数据值表现形式 PrintStream特点: 1.只负责数据的输入,不负责数 ...

  5. 【踩坑】mysql LIMIT 与 ORDER BY位置问题

    今天在重做iblog项目后台时,当测试功能,发现后台报错,位置在 MyBatis 向 MySQL 取数据时的语法问题,如下: SELECT * FROM article WHERE authorID ...

  6. java基础知识——Java的定义,特点和技术平台

    (作者声明:对于Java编程语言,很多人只知道怎么用,却对其了解甚少.我也是其中一员.所以菜鸟的我,去查询了教科书以及大神的总结,主要参考了<Java核心技术>这本神作.现在分享给大家!) ...

  7. 谈谈我对MVC的View层实现的理解

    MVC框架可以把应用清晰明了地分为三个部分:Model层–数据层,View层–视图层,Controller–逻辑层,Model层负责整合数据,View层负责页面渲染,Controller层负责实现业务 ...

  8. 一个容易被忽视的css选择器

    之前学的的迷糊了,也不知道什么会什么不会了,跑去面试了.别人列出一堆css选择器,本以为选择器没啥的,结果到那个多类选择器翻车了,.a.b选择同时含a,b类名的,很尴尬所以回来仔细整理了一下.目前根据 ...

  9. [转]git修改远程仓库地址

    原文链接:http://www.cnblogs.com/lazb/articles/5597878.html 问:Coding远程仓库地址变了,本地git仓库地址如何更新为最新地址 git修改远程仓库 ...

  10. bzoj4393: [Usaco2015 Dec]Fruit Feast

    题意: T,A,B.T是上限.A和B可以随意吃但是不能超过T.有一次将吃的东西/2的机会.然后可以继续吃,不能超过T.问最多可以吃多少. =>我们先处理不能/2可以吃到哪些.然后弄个双指针扫一扫 ...