zoukankan      html  css  js  c++  java
  • Codeforces 1019C Sergey's problem 构造

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1019C.html

    题目传送门 - CF1019C

    题意

      给定一个有 $n$ 个节点 、 $m$ 条边的有向图,没有自环,但是可能存在环。

      现在要求选出一个点集满足一下条件。

      设原来的所有点构成的点集为 $V$ ,选出的点集为 $S$,则:

      1. 对于所有满足 $x,yin S$ 的点 $x,y$ ,有向边 $(x,y)$ 不存在。

      2. 对于所有满足 $yin V$ 的点,都可以找到一个点 $x(xin S)$,满足从点 $x$ 开始走到 $y$ 的最少经过边数不超过 2 。

      首先输出你选出的点数,然后按照编号从小到大输出你选的点。

      $n,mleq 10^6$

    题解

      我们考虑以下构造方案:

      1. 记当前的图为 $G(V,E)$ 。

      2. 选择一个节点 $Ain V$ ,从 $G$ 中删除节点 $A$ ,以及从 $A$ 出发的有向边连向的所有节点,得到新图 $G^prime$ 。

      3. 如果 $V^prime eq emptyset $ ,则返回第 1. 步。否则到第 4 步。

      4. 记之前选出的所有节点 $A$ 构成的集合为 $v$ ,取 $v$ 和 原图 $G$ 中只与 $v$ 中的点有关边集 $e$ ,构成新图 $g(v,e)$ 。容易得知,$g$ 是一个有向无环图。

      5. 记当前的图为 $g(v,e)$ 。

      6. 取一个入度为 $0$ 的节点 $a$ ,并将该节点加入答案集合 $S$,删除 $a$ 以及在 $g$ 中 $a$ 能一步走到的所有点。设得到的新图的点集为 $v^prime$ 。

      7. 如果 $v^prime eq emptyset$ ,则返回第 1. 步。否则输出答案集合 $S$ 。

      现在简单的说明一下这样做的正确性:

        ① 首先,显然任意两个属于答案集合点不能一步到达。

        ② 对于任意满足 $xin v,x otin S$ 的节点 $x$ ,它只可能在第 6 步被删除,那么,显然有一个能一步达到 $x$ 的节点被记入答案。

        ③ 对于任意满足 $xin V,x otin v$ 的节点 $x$ ,它只可能在第 2 步的时候被删除,那么,显然有一个能一步到达 $x$ 的节点 $y$ 在集合 $v$ 中。又根据 ② ,如果 $y otin S$ ,有一步到 $y$ 的节点,则 $x$ 可以花两步到达;否则,$yin S$ ,$x$ 可以由 $y$ 一步到达。

        ④ 由于属于答案集合的节点显然可以在 2 步以内到达,再根据 ②③ ,上述做法的正确性显然。

      接下来就只差一个方便的实现方法了,详见代码。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1000005;
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    	return x;
    }
    void write(int v){
    	int k=v/10;
    	if (v>9)
    		write(k);
    	putchar('0'+(v-k*10));
    }
    struct Gragh{
    	static const int M=1000005;
    	int cnt,y[M],nxt[M],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m;
    int vis[N],ans[N],anscnt=0;
    int main(){
    	n=read(),m=read();
    	g.clear();
    	for (int i=1;i<=m;i++){
    		int a=read(),b=read();
    		g.add(a,b);
    	}
    	for (int i=1;i<=n;i++)
    		if (!vis[i]){
    			vis[i]=-2;
    			for (int j=g.fst[i];j;j=g.nxt[j])
    				vis[g.y[j]]=min(vis[g.y[j]],-1);
    		}
    	for (int i=n;i>=1;i--)
    		if (vis[i]==-2){
    			ans[++anscnt]=i;
    			for (int j=g.fst[i];j;j=g.nxt[j])
    				vis[g.y[j]]=-1;
    		}
    	write(anscnt),puts("");
    	for (int i=anscnt;i>=1;i--)
    		write(ans[i]),putchar(' ');
    	return 0;
    }
    

      

  • 相关阅读:
    element ui 表单清空
    element ui 覆盖样式 方法
    element ui 修改表单值 提交无效
    element ui 抽屉里的表单输入框无法修改值
    element ui 抽屉首次显示 闪烁
    css 左侧高度 跟随右侧内容高度 自适应
    PICNUF框架
    elementui 抽屉组件标题 出现黑色边框
    vue 子组件跨多层调用父组件中方法
    vue 编辑table 数据 未点击提交,table里的数据就发生了改变(深拷贝处理)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF1019C.html
Copyright © 2011-2022 走看看