找朋友
【试题描述】
老师要去统计班里的人际情况。
班里共有n名同学,编号从1到n。班上共有m对朋友。
现在,老师希望快速地知道,每名同学都有哪些朋友。
【输入要求】
输入的第一行包含两个整数n, m。
接下来m行,每行2个正整数编号,表示这两名同学是朋友。
【输出要求】
输出共n行,第i行的格式为:Friends of i : i所有朋友的编号。注意后输入的朋友先输出,详见样例。
【输入实例】
6 5 1 2 1 6 4 5 1 4 5 6
【输出实例】
Friends of 1 : 4 6 2 Friends of 2 : 1 Friends of 3 : Friends of 4 : 1 5 Friends of 5 : 6 4 Friends of 6 : 5 1
【其他说明】
对于40%的数据,n<=1000;
对于100%的数据,n<=100000,m<=200000。
【试题分析】
想想要用什么做?果断!第一反应:邻接矩阵and并查集
#include<iostream> using namespace std; int f[301000],a[301000][301000],k[301000],maxn; void cy(int f[],int x,int y) { int t=f[x],t1=f[y]; for(int i=0;i<1010;i++) if(f[i]==t) f[i]=t1; } int main() { int num=0,n,i,m,x,y; scanf("%d%d",&m,&n); for(i=0;i<1010;i++) f[i]=i; for(i=0;i<n;i++) { scanf("%d%d",&x,&y); maxn=max(maxn,max(x,y)); if(f[x]==f[y]); else cy(f,x,y); a[x][k[x]++]=y,a[y][k[y]++]=x; } for(int i=1;i<=maxn;i++) { cout<<"Friends of "<<i<<" :"; for(int j=k[i]-1;j>=0;j--) cout<<" "<<a[i][j]; cout<<endl; } }
如果你是这样按邻接矩阵开一个可怕的二维数组的话,恭喜你,内存爆了,电脑炸了。要是这样你还不如干脆开小一点空间,这样不至于一上来直接就炸内存,我们还可以骗一点分。
很显然,正解是不会让你有机会开二维数组的,3十万乘3十万。
而还有一种神奇的方法:邻接表。
我们可以试一试这个程序:
int n,m,i; int u[1006],v[1006]; int first[1005],next[1005]; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) first[i]=-1; for(int i=1;i<=m;i++) { scanf("%d%d",&u[i],&v[i]); next[i]=first[u[i]]; first[u[i]]=i; } for(i=1;i<=n;i++) { int k=first[i]; while(k!=-1) { printf("%d %d",u[k],v[k]); k=next[k]; }
cout<<endl; }
加上正规语法后,运行一下,看看有没有什么发现?
很明显输出的是:
1 41 61 2 4 5 5 6
啊!!第一行表示第一个人与四六二是朋友,与输出样例一样!
但是2的时候怎么没有输出1??
很明显,上面只输出了前面没有输出过的。
那么,怎么输出后面的呢?
我们要解决两个难题:
1.输出后面的。
2.后输入的先输出。
其实只要解决第一个,第二个就自然而然解决了。
我们只需双向储存一下就可以了。
既然要双向储存,我们就必须数组开两倍大。注意!少开的代价是很惨的!少乘一个二可能会在全国联赛中直接丢掉30+分!!而这三十分可能让你从银牌获得金牌或进入国家队!!
【代码】
#include<iostream> #include<cstring> using namespace std; inline int read() { int x,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); return x*f; } int u[200100],v[200100]; int first[400200],next[400200]; int main() { int n=read(),m=read(),k; memset(first,-1,sizeof(first)); for(int i=1;i<=m*2;i+=2) { u[i]=read(),v[i]=read(); u[i+1]=v[i],v[i+1]=u[i];//双向储存 next[i]=first[u[i]]; first[u[i]]=i; next[i+1]=first[u[i+1]]; first[u[i+1]]=i+1; } for(int i=1;i<=n;i++) { k=first[i]; printf("Friends of %d :",i); if(first[i]==-1) {printf(" ");continue;} while(k!=-1) { printf(" %d",v[k]); k=next[k]; } printf(" "); } }