题目大意:给一张图,要求你再尽可能的多连边,使得从1到2至少要经过5条边
考虑最后建成的图应该是什么样子的,我们可以把n个点划分成6个集合:1所在的集合,A,B,C,D,2所在的集合
然后相邻两个集合之间所有点连边,集合内所有点互相连边,其余没有边
首先可以证明1所在的集合={1},因为如果你放了其他点进来,他就只能和1还有A连边,不妨把他放到A里,使其还能和B连边
同理可证2所在的集合={2}
仔细思考一下发现其实A和D也已经确定好了,因为只有A集合里才能和1连边,所以初始图中和1有边的点就必须在A集合里,其他点一定可以不在A集合里(因为C集合的点个数大于等于1),同理可求出D集合
然后考虑剩下的点,他们互相之间是一定有边的,所以要让他们尽可能向外多连边,而他们向外只有两种可能,分到B集合向A连边或者分到C集合向D连边
由于AD已经确定,所以肯定是连向点数较多的那一边比较优
但是还有一些点不能随便连,比如初始图中就和A集合里的点有边,那他就一定不能去C集合,我们把类似这样的点挑出来,剩下的再贪心就好了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 2000010
#define N 40010
using namespace std;
int to[M],nxt[M],pre[N],cnt;
void ae(int ff,int tt)
{
cnt++;
to[cnt]=tt;
nxt[cnt]=pre[ff];
pre[ff]=cnt;
}
int spc[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int i,j,x,y;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
ae(x,y);ae(y,x);
}
int tot1=0,tot2=0,tot3,ans=0;
for(i=pre[1];i;i=nxt[i])
tot1++,spc[to[i]]=1;
for(i=pre[2];i;i=nxt[i])
tot2++,spc[to[i]]=2;
tot3=n-tot1-tot2-2;
ans=tot1*(tot1-1)/2+tot2*(tot2-1)/2+tot3*(tot3-1)/2+tot1+tot2;
int tmp1=0,tmp2=0;
for(x=3;x<=n;x++)
if(!spc[x])
{
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(!spc[j]) continue;
if(spc[j]==1) tmp1++;
else tmp2++;
break;
}
}
int re=tot3-tmp1-tmp2;
ans+=tmp1*tot1+tmp2*tot2+re*max(tot2,tot1);
printf("%d",ans-m);
}