题意:
给定一个包含N(1 ≤ N ≤ 10,000)个顶点的无向完全图,图中的顶点从1到N依次标号。从这个图中去掉M(0 ≤ M ≤ 1,000,000)条边,求最后与顶点1联通的顶点的数目。
思路:
由于数据过大,不能开矩阵直接存(会MLE)。所以每次只能判断某条边是否在删去边的集合中。
判断某条边是否在删去边的集合中的方法:
(1):直接查找O(n)
(2):二分查找O(logn)
(3):hash查找O(1)
PS.这个程序的快慢和hash函数的好坏有比较大的关系。
CODE:
/*BFS+hash(O(N^2))*/ /*AC代码:2719ms*/ #include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> #include <queue> #define MAXN 100007 #define P 9973 using namespace std; struct edge { int u,v,next; }hash[1000007]; int head[MAXN],ecnt; int N,M,cas; bool vis[MAXN]; queue<int>Q; void swap(int &a,int &b) { int t; if(a>b) {t=a;a=b;b=t;} } void Insert(int u,int v)//u<v { swap(u,v); int key=(u*P+v)%MAXN; hash[ecnt].u=u; hash[ecnt].v=v; hash[ecnt].next=head[key]; head[key]=ecnt++; } bool Judge(int u,int v) { int i; swap(u,v); int key=(u*P+v)%MAXN; for(i=head[key];i!=-1;i=hash[i].next) { if(hash[i].u==u&&hash[i].v==v) return true; } return false; } void Init() { int i,u,v; memset(head,-1,sizeof(head));ecnt=0; for(i=1;i<=M;i++) { scanf("%d%d",&u,&v); Insert(u,v); } } int BFS()//O(N^2) { int i,u,v; while(!Q.empty()) Q.pop(); memset(vis,false,sizeof(vis)); Q.push(1); vis[1]=true; while(!Q.empty()) { u=Q.front();Q.pop(); for(i=1;i<=N;i++) { if(vis[i]) continue;//保证每个点只被扩展一次 if(!Judge(u,i)) { vis[i]=true; Q.push(i); } } } int res=0; for(i=1;i<=N;i++) res+=vis[i]; return res-1; } void Solve() { int ans=BFS(); printf("Case %d: %d\n",cas++,ans); } int main() { cas=1; while(scanf("%d%d",&N,&M)!=EOF) { if(N==0&&M==0) break; Init(); Solve(); } return 0; }