zoukankan      html  css  js  c++  java
  • P5954 【[JSOI2013]侦探 JYY】

    来自一位神仙学长的思路,题意就不说了

    首先当前点被确定,那么他的所有儿子节点可以被确定

    考虑父亲节点。当存在两个以及两个以上的入度为(0)的点可以到达当前节点时,该点的父亲节点是不可以确定的,但是也许会推出其他有用的信息

    当数据是上面这样的时候,(3)是被确定的,(1)(2)可能被确定,但是(4)却能被确定,答案为(3)(4)。这应该是一组有用的数据,可以帮助更深的理解

    那么我们如何除了这些情况呢?

    我们可以预处理出所有节点的父亲节点(包括自己和祖先),并计算出最初的可以被确定的点的数量(sum)(即题目中的(b))

    假设当前处理的点为(x)(x)没被确定),我们把所有的点分为两类

    1. (x)的父亲节点和部分子节点

    2. (x)的父亲节点外中入读为(0)的点以及这些点的子节点

    可能说得不太清楚,画图来理解

    红色的即为第二类点,蓝色为第一类点,方框内的表示与(x)完全没有关系的点

    那么我们可以求出红色类点中,已经被确定的点的个数(tot):

    1. (tot=sum),说明蓝色类点中,没有可以被确定的点

    2. (tot<sum),说明蓝色类点中有其它已经被确定的点

    因为(x)是没有被确定的点(见上),那么与蓝色类点中其他被确定的点一定能推出来(x),这个结论也不是特别显然,建议自己手模一下

    由以上结论,我们可以知道(x)已经可以被确定了,此时(sum++)

    对于每个点进行上述处理之后,我们再对每一个被确定的点进行一次搜索,他的子节点一定是可以被确定的

    最后输出,结束

    可能不太清楚的可以看代码注释,结合上面分析

    #include<bits/stdc++.h>
    using namespace std;
    int head[200010],tot;
    struct node{
    	int net,to;
    }e[200010];
    int in[20010];
    void add(int x,int y){
    	e[++tot].net=head[x];
    	e[tot].to=y;
    	head[x]=tot;
    }
    int n,m,d;
    bool v[20010],vis[20010];
    set<int>fa[20010];
    void bfs(int x){
    	memset(vis,false,sizeof vis);
    	queue<int>q;
    	q.push(x);
    	vis[x]=true;
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		fa[u].insert(x);
    		for(int i=head[u];i;i=e[i].net){
    			int y=e[i].to;
    			if(vis[y]) continue;
    			q.push(y);
    			vis[y]=true; 
    		}
    	}
    }
    int sum;
    int fin(int x){
    	memset(vis,false,sizeof vis);
    	queue<int>q;
    	for(int i=1;i<=n;i++){
    		if(fa[x].find(i)==fa[x].end()&&!in[i]) q.push(i),vis[i]=true;
    		//表示红色类的点 
    	}
    	int tal=0;
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		tal+=v[u]; //统计个数 
    		for(int i=head[u];i;i=e[i].net){
    			int y=e[i].to;
    			if(vis[y]) continue;
    			q.push(y);
    			vis[y]=true;
    		}
    	}
    	return tal;
    }
    void bfs2(){
    	queue<int>q;
    	for(int i=1;i<=n;i++){
    		if(v[i]){
    			q.push(i);
    		}
    	}
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		for(int i=head[x];i;i=e[i].net){
    			int y=e[i].to;
    			if(v[y]) continue;
    			v[y]=true;
    			q.push(y);
    		}
    	} 
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&d);
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		in[y]++; //入度 
    	}
    	for(int i=1;i<=d;i++){
    		int x;
    		scanf("%d",&x);
    		v[x]=true; //可以被确定 
    		sum++; //已经确定的个数 
    	}
    	for(int i=1;i<=n;i++) bfs(i); //处理出每个点的父节点 
    	for(int i=1;i<=n;i++){
    		if(v[i]) continue;
    		if(fin(i)<sum){ //蓝色类点中有被确定的点 
    			v[i]=true;
    			sum++; //当前点可以被确定 
    		}
    	}
    	bfs2(); //把子节点标记一下 
    	for(int i=1;i<=n;i++){
    		if(v[i]) cout<<i<<" ";
    	}
    	return 0;
    }
    
  • 相关阅读:
    QT 中如何实现一个简单的动画
    qt 中画线时如何设置笔的颜色和填充
    QT自定义窗口
    qt 中创建一个工作线程(例子)
    QT 获取系统时间
    火狐浏览器 system error code 1722 rpc服务器不可用和谷歌浏览器的插件application/x-print-ladop不支持
    ORA-10858:在要求输入数字处找到非数字字符
    eaeyui-combobox实现组合查询(即实现多个值得搜索)
    Mybatis中的模糊查询
    如何设置像我这样的博客的样式。
  • 原文地址:https://www.cnblogs.com/Poetic-Rain/p/13669694.html
Copyright © 2011-2022 走看看