[BZOJ4478] [Jsoi2013]侦探jyy

来源:互联网 发布:北京大学网络公开课 编辑:程序博客网 时间:2024/04/27 02:41

[Jsoi2013]侦探jyy

Description
JSOI 的世界里一共有 N 个不同的事件( 依次由 1 到 N 编号),以及 M 条线索。
每一条线索对应一个二元组(x,y),表示事件 x 发生会导致事件 y 发生——注
意: 线索是单向的,也就是如果 y 发生了,并不代表 x 一定会发生。
线索是有传递性的, 即如果存在线索(x,y)以及(y,z), 那么 x 发生则会导致 z
发生。
同时由于世界是合理的,任意一个事件 x 一定不会通过某些线索导致事件 x
本身发生。
另外,整个世界仅包含这 M 条线索, 我们不认为一些事件会凭空发生(就
像福尔摩斯永远不会认为诡异的凶杀案是源于神的谴责)。具体而言: 对于某
个事件 x, 如果 x 发生了,并且存在某个事件可能导致 x 发生,那么一定至少有
一个可能导致 x 发生的事件发生了。
现在已知世界上的 M 条线索,以及 D 个已经发生的事件,那么由此推断,
哪些事件一定已经发生了呢?
Input
第一行包含用空格隔开的三个整数,分别为 N, M 和 D。
接下来 M 行,每行两个整数 x, y 表示线索(x,y), 满足 1 < = x, y < = N。
接下来 D 行为 D 个 1 到 N 之间不同的整数, 表示已知的已经发生的事件。
1 < = D < = N < = 1000, 1 < = M < = 100000
Output
包含一行至少 D 个由空格隔开的严格递增的正整数, 表示根据 M条线索以及 D 个已知事件
JYY 所能推断出的一定发生了的事件。
Sample Input
3 2 1
1 3
2 3
3
Sample Output
3
在第一个样例中,由于事件 1 和事件 2 这两个事件中的任何一个发生都会导致事件 3 发生,所以我们并不能确定到底哪个事件发生了。
在第二个样例中,由于事件 4 发生了,所以事件 2 和事件 3 中至少有一个发生了。而不论哪一个发生了,都可以推出事件 1 发生了。最终由于事件 1 发生了,使得我们可以推断出,所有 4 个事件都必然发生了。

Solution
枚举每一个事件,假设它不发生,那么它所有的前驱都不可能发生,在这种情况下我们贪心地让尽可能多的目前仍然能发生的初始事件(入度为0的事件)都发生,从而推得它们的后继都发生,此时我们再检查已知的那些点,假如已知的那些点仍然不能发生,那说明当前枚举的事件必然发生,因为当前事件不发生无法满足已知。

Code

#include <bits/stdc++.h>using namespace std;#define MS(_) memset(_,0,sizeof(_))template<typename T> inline void read(T &x){    x=0; T f=1; char ch=getchar();    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}    while (isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}    x*=f;}const int N=1100;const int M=100100;struct Node{int v;Node *nxt;}pool[M<<1],*tail=pool,*g[N],*fa[N];int n,m,d,know[N],p0[N],p1[N],q[N],cnt=0,ans[N];inline void addedge(int u,int v){    tail->v=v;tail->nxt=g[u];g[u]=tail++;    tail->v=u;tail->nxt=fa[v];fa[v]=tail++;}int main(){     read(n);read(m);read(d);        for(int i=1;i<=m;i++){ int u,v;        read(u);read(v);addedge(u,v);    }    for(int i=1;i<=d;i++){ int u;        read(u);know[u]=1;    }    for(int i=1;i<=n;i++) if (!know[i]){        MS(p0);MS(p1);int l,r,now;        for(p0[q[l=r=1]=i]=1;l<=r;l++)            for(Node *p=fa[q[l]];p;p=p->nxt)                if (!p0[p->v]) p0[q[++r]=p->v]=1;        for(int j=1;j<=n;j++) if (!fa[j]&&!p0[j]){            for(p1[q[l=r=1]=j]=1;l<=r;l++)                for(Node *p=g[q[l]];p;p=p->nxt)                    if (!p1[p->v]) p1[q[++r]=p->v]=1;        }        bool f=false;        for(int j=1;j<=n&&!f;j++) if (know[j]&&!p1[j]) f=true;        if(f) ans[++cnt]=i;    }else ans[++cnt]=i;    for(int i=1;i<cnt;i++) printf("%d ",ans[i]);printf("%d\n",ans[cnt]);    return 0;}
0 0
原创粉丝点击