zhber
有好多做过的题没写下来,如果我还能记得就补吧

Description

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,
查出谁是杀手。 
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他
认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。 
现在警察掌握了每一个人认识谁。 
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。 
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多
少?

Input

第一行有两个整数 N,M。 
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,例如***同志) 。

Output

仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。

Sample Input

5 4
1 2
1 3
1 4
1 5

Sample Output

0.800000

HINT

 

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警

察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概

率是0.8。对于 100%的数据有 1≤N ≤  10 0000,0≤M ≤  30 0000


数据已加强!

 
啊这题就有意思了
大致是给一个有向图,可以任选一个点开始搜索覆盖能走到的点,求用最少的点覆盖整张图,输出ans/n。
但是没那么简单……后面讲
考虑在一个环上的情况,显然任取一个点开始走就能走过整个环
那么环在本质上和一个点是一样的,只要查一次。所以上tarjan
tarjan完图被转换成DAG。答案就是入度为0的点的个数
但是这题的题目设置真TM好,还要带上各种特判
因为杀手只有一个,所以就一个点的时候查都不用查就是他了,输出1
还有:考虑如下哲♂学图
4 3
1 2
3 2
2 4
从1开始走能走到1、2、4,但是因为只剩下3这个点了所以其实3是不用查的
假设1、2、4中有杀手,那么3一定不是
假设1、2、4中没有杀手,那么3一定是
一句话,已经知道1、2、4的状态,就不用去查3了。
这个怎么特判?首先如果是环缩的点就不用特判了,肯定省不了的
对于每个点x,找所有它连出去的边指向的点ki,如果所有k的入度都>1(其中x->k有一条,如果还有其他点y可以到达k那么x不是必须的),那么mrk=1。最后如果mrk=1ans--就好了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x7ffffff
#define N 200010
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(LL a)
{
    if (a<0){printf("-");a=-a;}
    if (a>=10)write(a/10);
    putchar(a%10+'0');
}
inline void writeln(LL a){write(a);printf("\n");}
struct edge{int to,next;}e[10*N];
int head[N],belong[N],size[N];
int I[N],O[N];
bool inset[N];
bool mrk1[N],mrk2[N],ok;
int dfn[N],low[N];
int n,m,cnt,cnt3,tt,ans;
int zhan[N],top;
inline void ins(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
inline void dfs(int x)
{
    zhan[++top]=x;inset[x]=1;
    dfn[x]=low[x]=++tt;
    for(int i=head[x];i;i=e[i].next)
        if(!dfn[e[i].to])
        {
            dfs(e[i].to);
            low[x]=min(low[x],low[e[i].to]);
        }else if (inset[e[i].to])
        {
            low[x]=min(low[x],dfn[e[i].to]);
        }
    if (dfn[x]==low[x])
    {
        cnt3++;
        int p=-1;
        while(p!=x)
        {
            p=zhan[top--];
            belong[p]=cnt3;
            size[cnt3]++;
            inset[p]=0;
        }
    }
}
inline void tarjan()
{
    for(int i=1;i<=n;i++)if(!dfn[i])dfs(i);
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ins(x,y);
    }
    tarjan();
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=e[j].next)
        if (belong[i]!=belong[e[j].to])
        {
            I[belong[e[j].to]]++;
            O[belong[i]]++;
        }
    for(int i=1;i<=cnt3;i++)if (I[i]>1)mrk1[i]=1;
    memset(mrk2,1,sizeof(mrk2));
    for (int i=1;i<=n;i++)
        for (int j=head[i];j;j=e[j].next)
            if (belong[i]!=belong[e[j].to])
            {
                int x=belong[i],y=belong[e[j].to];
                if (!mrk1[y])mrk2[x]=0;
            }
    for(int i=1;i<=cnt3;i++)
    {
        if(size[i]==1&&!I[i]&&(!O[i]||mrk2[i]))ok=1;
        if(!I[i])ans++;
    }
    if (ok)ans--;
    printf("%.6lf\n",(double)(n-ans)/n);
}

 

posted on 2015-01-02 12:23  zhber  阅读(141)  评论(0编辑  收藏