无线广播(Broadcast)
https://dsa.cs.tsinghua.edu.cn/oj/course.shtml?courseid=59
描述
某广播公司要在一个地区架设无线广播发射装置。该地区共有n个小镇,每个小镇都要安装一台发射机并播放各自的节目。
不过,该公司只获得了FM104.2和FM98.6两个波段的授权,而使用同一波段的发射机会互相干扰。已知每台发射机的信号覆盖范围是以它为圆心,20km为半径的圆形区域,因此,如果距离小于20km的两个小镇使用同样的波段,那么它们就会由于波段干扰而无法正常收听节目。现在给出这些距离小于20km的小镇列表,试判断该公司能否使得整个地区的居民正常听到广播节目。
输入
第一行为两个整数n,m,分别为小镇的个数以及接下来小于20km的小镇对的数目。 接下来的m行,每行2个整数,表示两个小镇的距离小于20km(编号从1开始)。
输出
如果能够满足要求,输出1,否则输出-1。
输入样例
4 3
1 2
1 3
2 4
输出样例
1
限制
1 ≤ n ≤ 10000
1 ≤ m ≤ 30000
不需要考虑给定的20km小镇列表的空间特性,比如是否满足三角不等式,是否利用传递性可以推出更多的信息等等。
时间:2 sec
空间:256MB
解法1: bfs(STL)
扫描二维码关注公众号,回复:
5399071 查看本文章
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
#define IMAX 10100
vector<int> t;
vector< vector<int> > g(IMAX,t);
int n,m;
queue<int> qu;
int main() {
cin>>n>>m;
g.resize(n+1);
t.resize(n+1);
for(int i=1; i<=m; i++)
{
int a,b;
cin>>a>>b;
g[b].push_back(a); // 必须双向
g[a].push_back(b);
}
//bfs
for(int j=1; j<=n; j++)
{
if(t[j]) continue;
t[j]=1;
qu.push(j);
while(!qu.empty())
{
int cur=qu.front();
qu.pop();
for(int i=1; i<=g[cur].size(); i++)
{
if(t[g[cur][i]]==0)
{
t[g[cur][i]]=0-t[cur];
qu.push(g[cur][i]);
}
else if(t[g[cur][i]]+t[cur]!=0)
{
cout<<-1<<endl;
return 0;
}
}
}
}
cout<<1<<endl;
return 0;
}
解法2 (BSF)不使用STL
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define IMAX 10100
int t[IMAX]={
0
};
int icount[IMAX]={
0
};
int g[IMAX][IMAX/2];
int n,m;
int qu[IMAX*2];
int main() {
cin>>n>>m;
memset(icount,0,sizeof(icount));
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
if(b<a) swap(a,b);
g[a][++icount[a]]=b;
g[b][++icount[b]]=a;
}
//bfs
int index=-1,curindex=-1;
for(int j=1;j<=n;j++)
{
if(t[j]) continue;
t[j]=1;
qu[(++index)%(IMAX)]=j;
while(curindex!=index)
{
int cur=qu[++curindex];
for(int i=1;i<=icount[cur];i++)
{
//cout<<g[cur][i]<<"---"<<t[g[cur][i]]<<" "<<cur<<" "<<t[cur] <<endl;
if(t[g[cur][i]]==0)
{
t[g[cur][i]]=0-t[cur];
qu[(++index)%(IMAX)]=g[cur][i];
}
else if(t[g[cur][i]]+t[cur]!=0)
{
cout<<-1<<endl;
return 0;
}
}
}
index=-1,curindex=-1;
}
cout<<1<<endl;
return 0;
}
解法3 并查集
#include<cstdio>
#include<iostream>
#include <string.h>
using namespace std;
int f[10002],d[10002],n,m; //f保存祖先节点,d保存到其祖先节点的路径长。
int fa(int x)
{
if (f[x]!=x) //查找时沿途更新祖先节点和路径长。
{
int last=f[x]; //记录父节点(会在递归中被更新)。
f[x]=fa(f[x]); //更新祖先节点。
d[x]+=d[last]; //last 是原来的父亲 f[x] 就是根父亲
//下面调整后,d[x]+=d[last] d[last]只有一次为原父亲 ;
//更新路径长(原来连在父节点上)。
}
return f[x];
}
bool check(int a,int b)
{
int x=fa(a),y=fa(b);
if (x!=y) {
f[x]=y;
d[x]=d[b]+1-d[a];
}//这样设置之后,会将x和y同步}
else
{
if(abs(d[a]-d[b])%2==0)
{
cout<<-1<<endl;
return false;
}; //若已连接,则判断。
}
return true;
}
int main()
{
int i,t;
cin>>n>>m;
memset(d,0,sizeof(d));
for (i=1; i<=n; i++) f[i]=i; //祖先节点初始化为自己,路径长为0。
for(int i=1; i<=m; i++)
{
int a,b;
cin>>a>>b;
if(a>b) swap(a,b);
if(!check(a,b))
return 0;//检查当前两点是否已有边相连接。
}
cout<<1<<endl;
return 0;
}