CF1368E Ski Accidents

27 篇文章 0 订阅
16 篇文章 0 订阅

CF1368E Ski Accidents

  • 给一个每一个点出度不大于2的有向无环图。
  • 你需要删除最多 4 7 n \frac{4}{7}n 74n的点以及跟它们有关的边,使得最后图中不存在边数大于1的路径。
  • 输出任意一组方案。
  • n ≤ 2 e 5 n\le2e5 n2e5

Solution

  • 首先 4 7 \frac{4}{7} 74就很特别,再联系到每一个点的出度最多为2,应该发现这是一个 1 , 2 , 4 1,2,4 1,2,4的满二叉树,我们删去那 4 4 4个点。
  • 这启发我们,如果我们能够将 n n n个点分成三个集合 A , B , C A,B,C A,B,C A A A连向 B B B B B B连向 C C C,那么由于 2 ∣ A ∣ ≥ ∣ B ∣ , 2 ∣ B ∣ ≥ ∣ C ∣ 2|A|\ge|B|,2|B|\ge|C| 2AB,2BC C ≤ 4 7 n C\le\frac{4}{7}n C74n,只需要删掉 C C C就好了。
  • 要求是 A , B A,B A,B内部没有边。
  • 实际上我们一开始就可以想到一个很naive的想法,每隔 3 3 3个删一个点,看起来会有很多点重复,不好计算,但实际上我们只需要它们可以分成 3 3 3层,前一个集合向后一个集合连边,这样我们就可以保证集合 C C C的点数了。
  • 不妨按照拓扑序(也就是 1 1 1 n n n)做,如果一个点入度有 A A A但没有 B B B,那么它就是 B B B,入度有 B B B那么它就是 C C C,否则只有 C C C或没有入度它就是 A A A
  • 这样构造是满足条件的。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 200005
using namespace std;

int T,n,m,i,j,k,bz[maxn],c[3];
int em,e[maxn*2],nx[maxn*2],ls[maxn];

int main(){
	freopen("ceshi.in","r",stdin);
	scanf("%d",&T);
	while (T--){
		scanf("%d%d",&n,&m);
		em=0,memset(ls,0,sizeof(int)*(n+1));
		for(i=1;i<=m;i++){
			int x,y; scanf("%d%d",&x,&y);
			em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
		}
		int cnt=0;
		for(int x=1;x<=n;x++){
			c[0]=c[1]=c[2]=0;
			for(i=ls[x];i;i=nx[i]) c[bz[e[i]]]++;
			if (c[1]) bz[x]=2; else
			if (c[0]) bz[x]=1; else 
				bz[x]=0;
			cnt+=bz[x]==2;
		}
		printf("%d\n",cnt);
		for(i=1;i<=n;i++) if (bz[i]==2) printf("%d ",i);
		printf("\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值