JZOJ 5932. 【NOIP2018模拟10.27】情报中心

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangjingyuan107/article/details/83446772

题目

给定一个点数为n个图,m条边。
走一条边算1步。
共有q个询问
每个询问中有k个点,求有多少个点可以走最多v步走到询问中的任意一个点。
数据范围 n < = 1000 , m < = 100000 n<=1000,m<=100000

题解

其他猎奇的方法

一个O(mq)的失败方法:排个序做,每个点有一个状态t,表示点t仍可以走t的时间。
灵感来源于剩余相同的时间点可以一起做(序列中连续一段点的t都是相同的)。

正解

寻址优化。将前向星换成边集数组。
bitset替换统计哪些点是否出现过的bool数组。
spfa,其中不需要松弛。

反思

没拍,比赛快结束的时候发现有错,赶紧调,结果没有发现完所有的sb错误。
bitset操作:大佬的博客请点此处

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<bitset>
#include<algorithm>
#define N 1005
#define P(a) putchar(a)
using namespace std;
int i,j,k,l,n,m,q;
int cx[N],map[N][N];
int u,v,qu[N],dis[N];
bool Bz[N][N];
bitset<N>d[N][N],ans;
int read(){
	int fh=0,rs=0;char ch=0;
	while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
	if(ch=='-')fh=1,ch=getchar();
	while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
	return fh?-rs:rs;
}
void write(int x){
	if(x>9)write(x/10);
	P(x%10+'0');
}
int main(){
	freopen("center.in","r",stdin);
	freopen("center.out","w",stdout);
	n=read(),m=read(),q=read();
	for(i=1;i<=m;i++)u=read(),v=read(),(!Bz[u][v]?Bz[u][v]=Bz[v][u]=1,map[u][++cx[u]]=v,map[v][++cx[v]]=u:0);
	for(u=1;u<=n;u++){
		for(i=1;i<=n;i++)dis[i]=2139062143;
		dis[u]=0;
		qu[l=1]=u;
		for(i=1;i<=l;i++){
			v=qu[i];
			for(j=1;j<=cx[v];j++)(dis[map[v][j]]>dis[v]+1?dis[map[v][j]]=dis[v]+1,qu[++l]=map[v][j]:0);
		}
		for(i=1;i<=n;i++)(dis[i]<2139062143?d[u][dis[i]][i]=1:0);
		for(i=1;i<=n;i++)d[u][i]|=d[u][i-1];
	}
	while(q--){
		k=read();ans.reset();
		while(k--){
			u=read(),v=read();
			ans|=d[u][v];
		}
		write(ans.count()),P('\n');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangjingyuan107/article/details/83446772