题目地址:点击打开链接
题意:每2个城市间有一个权值,还有每次询问会给一个权值,城市间的权值小于询问的权值即可以走,问某个人能走多少对城市,注意(a,b),(b,a)算一对不同的城市
思路:刚开始用数组存储点和点的距离,然后每次搜强连通分量,搜出来强连通分量的个数不就是每个集合里面的个数么,假如说一个集合里面有n个值,那么总共有n(n-1)对,好理解吧,每个城市和其余城市连一次,不用除以2,因为(a,b),(b,a)算一对不同的城市,(可怜的我刚开始脑残,还还搞个函数求2C(n,2)的值,其实就是A(n,2),我擦),没想到直接MLE了,数组太大了,只能开数组保存每条边的信息,最后搞得太复杂,测试数据没过
下来看别人用并查集顿时傻逼了,我搜索也不就是为了求集合个数么,直接并查集不就搞定了,高兴的太早了,又T了好几次,对时间卡的特别严,在代码里细细分析
错误代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> using namespace std; int map1[20010][20010]; int visit[20010]; int n,maxq; int dfs(int x) { visit[x] = 1; int i,sum = 0; for(i=1; i<=n; i++) { if(map1[x][i] < maxq && !visit[i]) { sum++; sum += dfs(i); } } return sum; } int main() { int t,m,q; int a,b,c,l; int i,j,max1; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&q); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { map1[i][j] = INT_MAX; } } for(i=0; i<m; i++) { scanf("%d%d%d",&a,&b,&c); map1[a][b] = c; map1[b][a] = c; } for(i=0; i<q; i++) { max1 = 0; memset(visit,0,sizeof(visit)); scanf("%d",&maxq); for(j=1; j<=n; j++) { if(!visit[j]) { l = dfs(j); if(l > max1) max1 = l; } } n = (long long)n; max1 = (long long)max1; printf("%I64d\n",2*myc(max1+1,2)); } } return 0; }
超时代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> using namespace std; struct node { int value; int left; int right; bool operator < (const node &a) const { return value < a.value; } }a[100010]; int pre[20010],num[20010]; int find(int x) { int r = x,i = x,j; while(pre[r] != r) { r = pre[r]; } while(pre[i] != r)//路径压缩 { j = pre[i]; pre[i] = r; i = j; } return r; } void join(int x,int y) { int p = find(x); int q = find(y); if(p != q) { pre[p] = q; num[q] += num[p]; } } int main() { int t,i,j; int n,m,q; int x,y; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&q); for(i=0; i<m; i++) { scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].value); } sort(a,a+m); for(i=0; i<q; i++) { int maxq; scanf("%d",&maxq); for(j=1; j<=n; j++) { pre[j] = j; num[j] = 1; } for(j=0; j<m; j++) { if(a[j].value < maxq) { x = a[j].left; y = a[j].right; join(x,y); } if(a[j].value >= maxq) { break; } } int max1 = 0; for(j=1; j<=n; j++) { if(pre[j] == j) max1 += num[j] * (num[j] - 1); } printf("%d\n",max1); } } return 0; }
超时代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> using namespace std; struct node { int value; int left; int right; bool operator < (const node &a) const { return value < a.value; } } a[100010]; struct ask { int id; int value; bool operator < (const ask &a) const { return value < a.value; } } b[5010]; int pre[20010],num[20010]; int find(int x) { int r = x,i = x,j; while(pre[r] != r) { r = pre[r]; } while(pre[i] != r)//路径压缩 { j = pre[i]; pre[i] = r; i = j; } return r; } void join(int x,int y) { int p = find(x); int q = find(y); if(p != q) { pre[p] = q; num[q] += num[p]; } } int main() { int t,i,j; int n,m,q; int x,y; int ans[5010]; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&q); for(i=0; i<m; i++) { scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].value); } sort(a,a+m); for(j=1; j<=n; j++) { pre[j] = j; num[j] = 1; } for(i=0; i<q; i++) { scanf("%d",&b[i].value); b[i].id = i; } sort(b,b+q); j = 0; for(i=0; i<q; i++) { for(; j<m; j++) { if(a[j].value < b[i].value) { x = a[j].left; y = a[j].right; join(x,y); } if(a[j].value >= b[i].value) { break; } } int max1 = 0; for(j=1; j<=n; j++) { if(pre[j] == j) max1 += num[j] * (num[j] - 1); } ans[b[i].id] = max1; } for(j = 0; j < q; j++) printf("%d\n",ans[j]); } return 0; }
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <queue> #include <stack> #include <map> #include <cstring> #include <climits> #include <cmath> using namespace std; struct edge { int value; int left; int right; bool operator < (const edge &a) const { return value < a.value; } }a[100010]; struct query { int x,id; bool operator < (const query & a) const { return x < a.x; } }b[5010]; int pre[20010],num[20010],paixu[5010]; int find(int x) { return pre[x] == x ? x : pre[x] = find(pre[x]);//找老大加路径压缩 } /*void join(int x,int y) { int p = find(x); int q = find(y); if(p != q) { pre[p] = q; num[q] += num[p]; } }*/ //用上面那个join函数其实没有必要 void join(int x,int y) { pre[x] = y; num[y] += num[x]; } int main() { int t,i,j; int n,m,q; scanf("%d",&t); while(t--) { int ans = 0; scanf("%d%d%d",&n,&m,&q); for(i=1; i<=n; i++)//记得是从1开始赋值 { pre[i] = i; num[i] = 1; } for(i=0; i<m; i++) { scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].value); } sort(a,a+m); for(i=0; i<q; i++) { scanf("%d",&b[i].x); b[i].id = i; } sort(b,b+q); j = 0;//j就刚开始赋一个0即可 for(i=0; i<q; i++) { while(j<m && a[j].value <= b[i].x)//从上一次退出来的结果上接着搞,节省不少时间,每次从0开始搞也是错的,导致ans出错 { int left = find(a[j].left); int right = find(a[j].right); j++;//j++在前,不然continue退出就不加了 if(left == right) continue; ans += (num[left] + num[right])*(num[left] + num[right] - 1) - num[left] * (num[left] - 1) - num[right] * (num[right] - 1);//每次利用上面的结果递推很巧妙 join(left,right); } paixu[b[i].id] = ans; } for(i=0; i<q; i++) { printf("%d\n",paixu[i]); } } return 0; }