BZOJ2088: [Poi2010]Teleportation

题目大意:给一张图,要求你再尽可能的多连边,使得从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);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值