一定记得
pre[find(b)]=find(a)
题意:国王想要国家内的n个地点尽可能地连起来,就是n个点尽可能多的边啦(n*(n-1)/2)。但是有个限制就是,如果该节点是地方政治节点的话,它是不能和别的地方政治节点连起来的。题会给n个节点,k个政治节点,以及已经修好的m条边,求最多还能修多少条路
我看到好多大爷交的代码都是dfs。。。我靠这也能搜索啊。。。。
我比赛的时候就瞎搞的,先统计最多多少条边,用并查集维护的话,接下来就是数学的事情了。。。
然而比赛的时候脑子不清楚。。。。过程变量名写错了啥的,。。。。
话说我的莫名其妙变量取名习惯确实该改改了。。。赛后看自己代码简直是个啥玩意儿啊咋回事啊
#include <string.h>
#include <stdio.h>
#include <math.h>
//#include <iostream>
//using namespace std;
const int maxn = 1010;
bool vis[maxn];
bool cou[maxn];
int killme[maxn];
int pre[maxn];
int find(int x){
return pre[x]==x?x:pre[x]=find(pre[x]);
}
void join(int a,int b){
//pre[b]=a; 居然是这里让我MLE,路经压缩很重要啊!!
pre[find(b)]=find(a);
}
int main(){
int n,m,i,j,k,a,b;
memset(vis, false, sizeof(vis));
memset(killme, 0, sizeof(killme));
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++){
pre[i] = i;
}
for(i=1;i<=k;i++){
scanf("%d",&a);
vis[a] = true;
}
for(i=1;i<=m;i++){
scanf("%d%d",&a,&b);
join(a, b);
}
int ans = n*(n-1)/2;
memset(cou, false, sizeof(cou));
for(i=1;i<=n;i++){
find(i);
}
for(i=1;i<=n;i++){
if(vis[i]){
cou[pre[i]] = true;
}
killme[pre[i]]++;
}
int teki = 0;
for(i=1;i<=n;i++){
if(cou[i]){
teki += killme[i];
}
}
int now = teki;
for(i=1;i<=n;i++){
if(cou[i]){
ans -= killme[i]*(now-killme[i]);
now -= killme[i];
}
}
int connect;
killme[connect] = 0;
for(i=1;i<=n;i++){
int bojack = pre[i];
if(!cou[bojack]){
now = 0;
connect = 0;
for(j=1;j<=n;j++){
if(cou[j]){
if(killme[j]>now){
connect = j;
now = killme[connect];
}
}
}
ans -= (killme[bojack]*(teki-killme[connect]));
killme[connect] += killme[bojack];
cou[bojack] = true;
teki += killme[bojack];
}
}
printf("%d\n",ans-m);
return 0;
}