HDU 5876 Sparse Graph 【补图最短路 BFS】(2016 ACM/ICPC Asia Regional Dalian Online)

Sparse Graph

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 704    Accepted Submission(s): 241


Problem Description
In graph theory, the  complement  of a graph  G  is a graph  H  on the same vertices such that two distinct vertices of  H  are adjacent if and only if they are  not adjacent in  G

Now you are given an undirected graph  G  of  N  nodes and  M  bidirectional edges of  unit  length. Consider the complement of  G , i.e.,  H . For a given vertex  S  on  H , you are required to compute the shortest distances from  S  to all  N1  other vertices.
 

Input
There are multiple test cases. The first line of input is an integer  T(1T<35)  denoting the number of test cases. For each test case, the first line contains two integers  N(2N200000)  and  M(0M20000) . The following  M  lines each contains two distinct integers  u,v(1u,vN)  denoting an edge. And  S (1SN)  is given on the last line.
 

Output
For each of  T  test cases, print a single line consisting of  N1  space separated integers, denoting shortest distances of the remaining  N1  vertices from  S  (if a vertex cannot be reached from S, output ``-1" (without quotes) instead) in ascending order of vertex number.
 

Sample Input
  
1 2 0 1
 

Sample Output
  
1
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5877  5875  5874  5873  5872 
 

Statistic |  Submit |  Discuss |  Note


题目链接:

  http://acm.hdu.edu.cn/showproblem.php?pid=5876

题目大意:

  给你N个点M条无向边的一张图G(2<=N<=200000,0<=M<=20000),并给定起点S,边权均为1,求在这张图的补图H上S到其他N-1个点的最短路,无法到达为-1。

  补图:在原图G上X和Y之间有一条边,则补图上X和Y之间没有相连的边,在原图X和Z之间没边,那么在补图上X和Z之间有一条边。

题目思路:

  【补图最短路】【宽搜】

  比赛的时候数据范围写错了导致队列开小了。WA了。。然而队友神奇的map[5500][5500]居然过了。。不是很懂。。

  首先分析一下原图G,如果存在孤立点X(不与任何点相连),那么在补图上这个点X与其他所有的点相连,所以d[X]=1。

    对于其余点Y,若Y与S相连则Y的最短路为S->X->Y,d[Y]=2,否则即为S->Y,d[Y]=1。(当N>M+1时必有孤立点)

  再考虑没有孤立点的情况,对于原图G,先将S能够到达的点和不能到达的点分为两个集合T和Q,易知Q中所有的点d[i]=1

  接着,将Q中的所有点做一次宽搜(最短路SPFA),每个点能够到达的在T中的点d++,Q中所有的点都做完后判断T中的点

  对于T中的点X,如果X在原图不能被Q中所有的点走到,那么在补图中一定有一条边从Q中的点Y连向X,则d[X]=d[Y]+1,

  如果被Q中所有点走到,那么这个点继续留在X中等待下一次。

  做完一次后,继续对新加入Q中的节点做宽搜(最短路SPFA),直到没有新节点加入Q。

  如果此时T中还有点则为走不到的,d=-1。

  最后输出答案即可。注意多余空格会PE。

  注释见代码。



//
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<bitset>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-10)
#define J 10000
#define mod 1000000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define N 200004
#define M 20004
using namespace std;
typedef long long LL;
double anss;
LL aans;
int cas,cass;
int n,m,lll,ans;
int S;
int last[N],d[N];
char ch;
int q[M],t[M];
struct xxx
{
	int to,next;
}a[M<<1];
bool mark[N];
void add(int x,int y)
{
	a[++lll].to=y;
	a[lll].next=last[x];
	last[x]=lll;
}
void work1()
{
	int i;
	for(i=1;i<=n;i++)d[i]=1;
	for(i=last[S];i;i=a[i].next)d[a[i].to]+=1;//孤立点情况与S相连的点答案为2,其余为1
	for(i=1;i<=n;i++)
	{
		if(i==n || (i==n-1 && S==n))ch='\n';
		else ch=' ';
		if(i==S)continue;
		printf("%d%c",d[i],ch);
	}
}
void spfa()
{
	int i,now,to,l=1,r=1,x=0,y=0,sz;
	mem(mark,0);
	for(i=1;i<=n;i++)d[i]=mark[i]=1;//初始化
	q[1]=S;mark[S]=1;d[S]=0;
	for(i=last[S];i;i=a[i].next)mark[a[i].to]=0;
	for(i=1;i<=n;i++)//将所有点分成两类
	{
		if(i==S)continue;
		if(mark[i])
			q[++r]=i;//与S不相连的,d=1
		else
			t[++y]=i;//与S相连的,需要进一步判断
	}
	while(l<r)
	{
		while(l<r)//将Q中新加入的点now往T集合的点走,每走到一个在T中的点x,d[x]++
		{
			now=q[++l];
			for(i=last[now];i;i=a[i].next)
			{
				to=a[i].to;
				if(mark[to])continue;
				d[to]++;
			}
		}
		sz=r;//sz为Q集合的大小,如果在T中的点x在补图中有连向Q的边,那么d[x]<sz(在原图上x不被所有Q中的点走到)
		for(i=1,x=0;i<=y;i++)
		{
			now=t[i];
			if(d[now]==sz)
				t[++x]=now;//被所有点走到,继续留在T中
			else
			{
				q[++r]=now;//将这个点加入Q中
				d[now]=d[q[l]]+1;//这个点的距离为上一个距离+1
				mark[now]=1;//标记为在Q中
			}
		}
		y=x;//T的新大小
	}
	for(i=1;i<=y;i++)d[t[i]]=-1;//若Q中的点都遍历完,T中还有剩余的点,则为走不到的点,d=-1
	for(i=1;i<=n;i++)
	{
		if(i==n || (i==n-1 && S==n))ch='\n';
		else ch=' ';
		if(i==S)continue;
		printf("%d%c",d[i],ch);
	}
}
int main()
{
	#ifndef ONLINE_JUDGE
//	freopen("1.txt","r",stdin);
//	freopen("2.txt","w",stdout);
	#endif
	int i,j,k;
	int x,y,z;
//	init();
	for(scanf("%d",&cass);cass;cass--)
//	for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
//	while(~scanf("%s",s))
//	while(~scanf("%d",&n))
	{
		lll=cas=0;mem(last,0);mem(mark,0);
		scanf("%d%d",&n,&m);
		for(i=1;i<=m;i++)
		{
			scanf("%d%d",&x,&y);
			add(x,y),add(y,x);
			if(!mark[x])mark[x]=1,cas++;
			if(!mark[y])mark[y]=1,cas++;
		}
		scanf("%d",&S);
		if(cas<n)work1();//孤立点情况
		else spfa();//无孤立点情况
	}
	return 0;
}
/*
//

//
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值