【清北前紧急补课10】并查集

1.团伙

题目描述

1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是:

我朋友的朋友是我的朋友;

我敌人的敌人也是我的朋友。

两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。

输入输出格式

输入格式:

 

输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。 第二行M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。输入数据保证不会产生信息的矛盾。

 

输出格式:

 

输出文件gangs.out只有一行,表示最大可能的团伙数。

 

输入输出样例

输入样例#1:  复制
6
4
E 1 4
F 3 5
F 4 6
E 1 2
输出样例#1:  复制
3

并查集和反集的思想。
即朋友是x 敌人x+n
我们可以这样理解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,s,d;
char ch;
int f[2010];

int find(int x){
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}

void unionn(int x,int y){
    int x1=find(x);int y1=find(y);
    if(x1!=y1) f[y1]=x1;
}

int main(){
    cin>>n;
    for(int i=1;i<=n*2;i++) f[i]=i;
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>ch>>s>>d;
        if(ch=='F') unionn(s,d);
        else{
            unionn(s,d+n);
            unionn(d,s+n);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) {
        if(f[i]==i) ans++;//这里再解释一下吧,只有父节点是自己的“祖宗”才能代表有一个团伙,用ans来记录团伙的数量。
    }
    cout<<ans; 
} 

2.关押罪犯

题目描述

SS 城现有两座监狱,一共关押着 NN 名罪犯,编号分别为 1-N1N 。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 cc 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 cc 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了 NN 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入输出格式

输入格式:

 

每行中两个数之间用一个空格隔开。第一行为两个正整数 N,MN,M ,分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的 MM 行每行为三个正整数 a_j,b_j,c_jaj,bj,cj ,表示 a_jaj 号和 b_jbj 号罪犯之间存在仇恨,其怨气值为 c_jcj 。数据保证 1<aj≤bj≤N ,0 < cj≤ 1,000,000,0001<ajbjN,0<cj1,000,000,000 ,且每对罪犯组合只出现一次。

 

输出格式:

 

共 11 行,为 ZZ 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出 00 。

 

输入输出样例

输入样例#1:  复制
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884
输出样例#1:  复制
3512

说明

【输入输出样例说明】罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件影响力是 35123512 (由 22 号和 33 号罪犯引发)。其他任何分法都不会比这个分法更优。

【数据范围】

对于 30\%30% 的数据有 N≤ 15N15 。

对于 70\%70% 的数据有 N≤ 2000,M≤ 50000N2000,M50000 。

对于 100\%100% 的数据有 N≤ 20000,M≤ 100000N20000,M100000 。

我们可以这么理解 要把怒气值最大的两位尽可能关在两个监狱里,然后再考虑次大的,依次类推。这样我们就可以想成 把和a怒气值最大的b b的怒气值最大的c 要是a和c的怒气值允许的话 就把a和c关在一起 所谓敌人的敌人就是朋友。
那我们要给是敌人的两个人做个标记 怎么做呢 将2倍的n初始化。设置2n个数组 x和x+n表示不同监狱 y和y+n表示不同监狱 在合并前看看x和y x+n和y+n是不是在同一个监狱里 在的话次是的影响力就是最大了啊,如果不是就合并x和y+n,y和x+n。
就是这样。

#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[100010],d[100010];
int n,m; 

struct dataa{
    int x,y;
    int sum;
}a[200010];

bool cmp(dataa x,dataa y){
    return x.sum>y.sum;
}

int find(int x){
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}

void unionn(int x,int y){
    int x1,y1;
    x1=find(x),y1=find(y);
    if(x1!=y1) f[y1]=x1;
}

bool pd(int x,int y){
    if(find(x)==find(y)) return true;
    return false;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n*2;i++) f[i]=i;
    for(int i=1;i<=m;i++) cin>>a[i].x>>a[i].y>>a[i].sum;
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++){
        int s=a[i].x,z=a[i].y;
        if(pd(s,z)||pd(s+n,z+n)) {
            cout<<a[i].sum;
            return 0;
        }
        unionn(s,z+n);
        unionn(s+n,z);
    }
    cout<<0;
} 

3.食物链

题目描述

动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B

吃 C,C 吃 A。

现有 N 个动物,以 1 - N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道

它到底是哪一种。

有人用两种说法对这 N 个动物所构成的食物链关系进行描述:

第一种说法是“1 X Y”,表示 X 和 Y 是同类。

第二种说法是“2 X Y”,表示 X 吃 Y 。

此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真

的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

• 当前的话与前面的某些真的话冲突,就是假话

• 当前的话中 X 或 Y 比 N 大,就是假话

• 当前的话表示 X 吃 X,就是假话

你的任务是根据给定的 N 和 K 句话,输出假话的总数。

输入输出格式

输入格式:

 

从 eat.in 中输入数据

第一行两个整数,N,K,表示有 N 个动物,K 句话。

第二行开始每行一句话(按照题目要求,见样例)

 

输出格式:

 

输出到 eat.out 中

一行,一个整数,表示假话的总数。

 

输入输出样例

输入样例#1:  复制
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
输出样例#1:  复制
3

说明

1 ≤ N ≤ 5 ∗ 10^4

1 ≤ K ≤ 10^5

 

跟上边那两个差不多,就是有三个并查集

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=50010;
int n,x,y;
int f[maxn*3],k;
int ch,ans;
/*
x存本身 x+n存猎物 x+2n存敌人 
*/ 

int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}

void unionn(int x,int y){
    int x1=find(x),y1=find(y);
    if(x1!=y1) f[y1]=x1;
}

int main(){
    cin>>n>>k;
    for(int i=1;i<=n*3;i++) f[i]=i;
    for(int i=1;i<=k;i++){
        cin>>ch>>x>>y;
        if(x>n||y>n) {
            ans++;
            continue;
        }//不属于该食物链 
        if(ch==1){
            if(find(x+n)==find(y)||find(x+2*n)==find(y)){
                ans++;continue;
            }//x 和 y是猎物或者敌人的关系 为谎言 
            unionn(x,y);unionn(x+n,y+n);unionn(x+2*n,y+2*n);//如果为真 将 x 和 y 放入一个并查集中 
        }
        else if(ch==2){
            if(x==y){
                ans++;continue;
            }  
            if(find(x)==find(y)||find(x+2*n)==find(y)){
                ans++;continue;
            }// x是y的同类或者x是y的猎物 则是谎言 
            unionn(x,y+2*n);unionn(x+n,y);unionn(x+2*n,y+n);//如果 这句话是真的 那么 x的同类 吃 y ;x 吃 y的同类 ;y 吃 吃x的z。 
        }
    }
    cout<<ans;
}

 

转载于:https://www.cnblogs.com/civilization-ga/p/9453052.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值