题目链接: hdu 2463
题目大意: 给出N(N<=10000)个点的无向完全图
现在删掉M条边,问能从1顶点遍历到的顶点有多少个?
解题思路: 1W个点的完全图有n*(n-1)/2条边,不能直接建图,空间复杂度太高
只需要记录那些边是已经删除掉了的,删除掉的边用Hash(a+b*10000)记录(或map)
把没访问过的点用链表串起来,不能直接用visit[ ]记录,因为每次遍历很耗时
也可以用STL库中的set容器存储起来,但STL效率较低
BFS每走到某个点时,判断它和没访问过的点中哪些有边,有则走到另一个点
PS: Hash的效率比map高,但map可以保证不冲突
代码(Hash+链表):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10003
#define MAX2 2800000
int visit[MAX],list[MAX*2],sum,Top;
int Hash[MAX2+1];
struct snode{
int w,next;
}Tree[MAX];
int BKDRHash(int k) //Hash判断边是否是不能走的
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;
while(k)
{
hash = (hash * seed + (k%10))%MAX2;
k/=10;
}
return (hash % MAX2);
}
void BFS(int Star) //从第一点开始BFS
{
int i,j,e,s,tempv,tempvv,a,b;
e=s=0;
list[s++]=Star;
visit[Star]=1;
while(e!=s)
{
tempv=list[e++];
for(i=Top,j=Top;i!=-1;i=Tree[i].next)
{
tempvv=Tree[i].w;
a=(tempv<tempvv)?tempv:tempvv;
b=(tempv<tempvv)?tempvv:tempv;
if(Hash[BKDRHash(a+b*10000)]!=1&&!visit[tempvv]) //若该边能走且该点为被访问
{
visit[tempvv]=1;
sum++;
if(i==Top) //是链表头则去掉
{
Top=Tree[i].next;
}
else //不是表头则跳过
{
Tree[j].next=Tree[i].next;
}
list[s++]=tempvv;
}
else if(i!=Top)
{
j=Tree[j].next;
}
}
}
return ;
}
int main()
{
int n,m,t=0,i,a,b,temp;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
sum=0;
memset(Hash,0,sizeof(Hash));
memset(visit,0,sizeof(visit));
memset(Tree,-1,sizeof(Tree));
Top=1;
Tree[1].w=1;
for(i=2;i<=n;i++) //创建链表
{
Tree[i-1].next=i;
Tree[i].w=i;
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(b<a)
{
temp=a;
a=b;
b=temp;
}
Hash[BKDRHash(a+b*10000)]=1; //记录哪些边不能走的
}
BFS(1);
printf("Case %d: %d\n",++t,sum);
}
return 0;
}
代码(Map+set):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#define MAX 10010
using namespace std;
set<int> Q; //**
set<int>:: iterator qi; //**
map<int,int> S[MAX];
int visit[MAX],list[MAX*2],sum;
void BFS(int Star)
{
int e,s,tempv,tempvv;
e=s=0;
list[s++]=Star;
visit[Star]=1;
Q.erase(Star);
while(e!=s)
{
tempv=list[e++];
for(qi=Q.begin();qi!=Q.end();) //**
{
tempvv=*qi; //**
if(S[tempv][tempvv]!=1&&!visit[tempvv]) //若该点可以访问,则从容器中去掉该点,并且加入队列
{
qi=Q.erase(qi); //**
sum++;
visit[tempvv]=1;
list[s++]=tempvv;
}
else //**
qi++;
}
}
return ;
}
int main()
{
int n,m,t=0,i,a,b;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
sum=0;
while(!Q.empty())
{
Q.clear();
}
for(i=1;i<=10002;i++)
{
S[i].clear();
}
memset(visit,0,sizeof(visit));
for(i=2;i<=n;i++)
{
Q.insert(i); //往set里面加入元素
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
S[a][b]=S[b][a]=1; //Map记录哪些边不能走
}
BFS(1);
printf("Case %d: %d\n",++t,sum);
}
return 0;
}