列表

详情


NC51312. 杀人游戏

描述

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

输入描述

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

输出描述

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

示例1

输入:

5 4 
1 2 
1 3 
1 4 
1 5 

输出:

0.800000

说明:

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 199ms, 内存消耗: 7328K, 提交时间: 2022-08-22 10:43:45

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node
{
    int to,nx;
}p[maxn*3];
struct node2
{
    int to,nx;
}q[maxn*3];
int n,m,dfn[maxn],low[maxn],head[maxn],tot,vis[maxn],scc[maxn],cnt,sz[maxn],d[maxn],head2[maxn];
double ans;
void addedge(int s,int t)
{
    p[++tot].to=t,p[tot].nx=head[s],head[s]=tot;
}
void addedge2(int s,int t)
{
    d[t]++;
    q[++tot].to=t,q[tot].nx=head2[s],head2[s]=tot;
}
stack<int>sk;
void tarjan(int cur)
{
    dfn[cur]=low[cur]=++tot;
    sk.push(cur);
    vis[cur]=1;
    for(int i=head[cur];i;i=p[i].nx)
    {
        int to=p[i].to;
        if(!dfn[to])
        {
            tarjan(to);
            low[cur]=min(low[cur],low[to]);     }
            else if(!scc[to]) low[cur]=min(low[cur],dfn[to]);
    }
    if(dfn[cur]==low[cur])
    {
        int now;
        cnt++;
        do
        {
            now=sk.top();
            sk.pop();
            vis[now]=0;
            scc[now]=cnt;
            sz[cnt]++;
        }while(now!=cur);
    }
}
int ok(int cur)
{
    if(d[cur]||sz[cur]!=1) return 0;
    for(int i=head2[cur];i;i=q[i].nx)
    {
        if(d[q[i].to]==1) return 0;
    }
    return 1;
}
void rebuild()
{
     
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=p[j].nx)
        {
            if(scc[i]!=scc[p[j].to]) addedge2(scc[i],scc[p[j].to]);
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        addedge(u,v);
         
    }
    tot=0;
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i);
    }
    tot=0;
    rebuild();
    for(int i=1;i<=cnt;i++)
    {
        if(!d[i]) ans++;
    }
    for(int i=1;i<=cnt;i++)
    {
        if(ok(i))
        {
            ans--;
            break;
        }
    }
    printf("%.6f",(double)(n-ans)/(double)n);
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 194ms, 内存消耗: 8052K, 提交时间: 2023-06-21 23:43:37

#include<bits/stdc++.h>
using namespace std;
int dfn[300005],lw[300005],h[300005],hh[300005],inv[300005],c[300005],st[300005],sze[300005],n,m,tot,cnt,top,u,v,C,dc,vis[300005],vv[300005],ff=1,pp=1;
struct asdf{int v,nxt;}e[600005],ee[600005];
struct asd{int u,v;}E[300005];
void ad(int u,int v){e[++tot].v=v;e[tot].nxt=h[u];h[u]=tot;}
void ae(int u,int v){ee[++tot].v=v;ee[tot].nxt=hh[u];hh[u]=tot;inv[v]++;}
void tarjan(int np){
	dfn[np]=lw[np]=++dc;
	st[++top]=np;vis[np]=1;
	for(int i=h[np];i;i=e[i].nxt){
		if(!dfn[e[i].v])tarjan(e[i].v),lw[np]=min(lw[np],lw[e[i].v]);
		else if(vis[e[i].v]&&dfn[e[i].v]<lw[np])lw[np]=dfn[e[i].v];
	}
	if(lw[np]==dfn[np]){C++;while(st[top+1]-np)vis[st[top]]=0,c[st[top]]=C,sze[C]++,top--;}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)cin>>E[i].u>>E[i].v,ad(E[i].u,E[i].v);
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
	tot=1;
	for(int i=1;i<=n;i++){
		for(int j=h[i];j;j=e[j].nxt)if(c[i]-c[e[j].v]&&!vv[c[e[j].v]])ae(c[i],c[e[j].v]),vv[c[e[j].v]]=1;
		for(int j=h[i];j;j=e[j].nxt)vv[c[e[j].v]]=0;
	}
	for(int i=1;i<=C;i++){
		if(!inv[i])cnt++;
		if(ff&&!inv[i]&&sze[i]<2){pp=1;for(int j=hh[i];j;j=ee[j].nxt)if(inv[ee[j].v]<2){pp=0;break;}if(pp)cnt--,ff=0;}
	}
	printf("%.6lf",(double)(n-cnt)/n);
    return 0;
}

上一题