zoukankan      html  css  js  c++  java
  • 【CF1019C】Sergey's problem

    题目

    题目链接:https://codeforces.com/problemset/problem/1019/C
    给定一张无自环的有向图,选出一个点集 (S),使得:

    1. (S) 中任意两个点的距离不小于 (2)
    2. 对于任意不在 (S) 中的点 (x),存在一个 (S) 中的点 (y) 使得 (y)(x) 的距离不大于 (2)

    输出任意一中解。
    (n,mleq 10^6)

    思路

    直接给解法:
    从小到大枚举所有点,如果这个点没有被标记,那么把这个点能一步到达的所有编号大于它的点标记。
    再从大到小枚举所有点,如果这个点没有被标记,那么把这个点能一步到达的所有编号小于它的点标记。
    最后没有被标记的点就是一个合法解。
    证明:
    记第一次被标记的点集为 (S_1),第二次被标记的点集为 (S_2),最后没有被标记的点集为 (S)
    (S) 中任意两个点距离肯定是不小于 (2) 的。否则被到达的点一定会被标记上。
    (S_2) 中每一个点都可以从 (S) 其中一个点一步到达,(S_1) 中每一个点都可以从 (S)(S_2) 其中一个点一步到达,也就是 (S_1cup S_2) 中所有点都可以通过 (S) 两步内到达。
    时间复杂度 (O(n+m))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=1000010;
    int n,m,tot,head[N];
    bool vis[N];
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1,x,y;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    	}
    	for (int i=1;i<=n;i++)
    		if (!vis[i])
    			for (int j=head[i];~j;j=e[j].next)
    				if (e[j].to>i) vis[e[j].to]=1;
    	for (int i=n;i>=1;i--)
    		if (!vis[i])
    			for (int j=head[i];~j;j=e[j].next)
    				if (e[j].to<i) vis[e[j].to]=1;
    	tot=0;
    	for (int i=1;i<=n;i++)
    		if (!vis[i]) tot++;
    	cout<<tot<<"
    ";
    	for (int i=1;i<=n;i++)
    		if (!vis[i]) cout<<i<<" ";
    	return 0;
    }
    
  • 相关阅读:
    CodeSmith中SchemaExplorer属性的介绍
    Bugku-INSERT INTO 注入
    XCTF-PHP2
    网络安全实验室CTF-注入关
    XSS挑战
    SQL注入
    CTFHub-技能树-命令执行
    CTFHub-技能树-文件上传
    史上最难的一道Java面试题 (分析篇)
    高可用的一些思考和理解
  • 原文地址:https://www.cnblogs.com/stoorz/p/15247984.html
Copyright © 2011-2022 走看看