抓小偷(强连通)

第4题     抓小偷 查看测评数据信息

你是一名警察,现在有一个案子交给你,N个人里面其中有一人是小偷,你的任务是查出来谁是小偷,你可以一个一个的盘问,假如盘问的对象不是小偷,他会告诉你,他认识谁,谁是好人,谁是小偷,假如你盘问的对象是小偷,小偷就会袭警,现在你掌握了每一个人认识谁。每一个人都有可能是小偷,可看作他们是小偷的概率是相同的。

问:根据最优的情况,保证警察自身安全并知道谁是小偷的概率最大是多少?

输入格式

 

第一行有两个整数 N,M。 对于100的数据有1≤N≤100000,0≤M≤300000。

接下来有 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。

 

 

 关键在于用缩点把图变成有向无环图

 

找需要查证的人即可,答案就是(总人数-需查证人数)/ 总人数

注意分类别漏了

先缩点,变有向无环图,剩下的就全是链了

1.链:搞入度为0的点,只需要问入度为0的点对应的那个人,剩下的人都可以被推出来
2.环:搞环中任何一个人 (情况排除了,因为缩点后不存在环)
3.判断入度为0的点可否用排除法,设排除u
1)size[u]==1,不能是缩点后的一个胖点,排除法只能排除一个人
2)u的所有儿子son入度>1,不然你排除了u点,他的儿子身份也无法确定
4.图只有一个点,直接100%,因为他只能是小偷

 

#include <bits/stdc++.h>
using namespace std;
const int N=600005;

int n, m, u1, v1, dfn[N], low[N], idx=0, cnt=0, id[N], rd[N], ans=0, size[N];
bool vis[N], flag=0;
stack<int> st;
vector<int> a[N], b[N];
void dfs(int u)
{
	dfn[u]=low[u]=++idx;
	st.push(u);
	
	for (int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if (!dfn[v])
		{
			dfs(v);
			low[u]=min(low[u], low[v]);
		}
		else if (!id[v]) low[u]=min(low[u], dfn[v]);
	}
	
	if (dfn[u]==low[u])
	{
		cnt++;
		while (st.top()!=u)
		{
			id[st.top()]=cnt;
			size[cnt]++;
			st.pop();
		}
		id[st.top()]=cnt;
		size[cnt]++;
		st.pop();
	}
}
bool check(int x)
{
	if (rd[x]!=0 || size[x]>1)	return false;
	for (int i=0; i<b[x].size(); i++)
		if (rd[b[x][i]]<=1) return false; 
	
	return true; 
}
int main()
{
	scanf("%d%d", &n, &m);
	if (n==1)
	{
		printf("1.000000");
		return 0;
	}
	for (int i=1; i<=m; i++)
	{
		scanf("%d%d", &u1, &v1);
		a[u1].push_back(v1);
	}
	
	for (int i=1; i<=n; i++)
		if (!dfn[i]) dfs(i);
	
	for (int u=1; u<=n; u++)
	{
		for (int j=0; j<a[u].size(); j++)
		{
			int v=a[u][j];
			if (id[u]==id[v] || vis[id[v]]) continue;
			
			b[id[u]].push_back(id[v]);
			rd[id[v]]++, vis[id[v]]=1;
		}
		for (int j=0; j<a[u].size(); j++) vis[id[a[u][j]]]=0;
	}
	/*for (int u=1; u<=cnt; u++)
	{
		printf("%d :  {", u);
		for (int j=0; j<b[u].size(); j++)
		{
			printf("%d ", b[u][j]);
		}
		printf(" }\n");
	}*/
		
	for (int i=1; i<=cnt; i++) if (!rd[i]) ans++;
	for (int i=1; i<=cnt; i++)
		if (check(i))
		{
			ans--;
			break;
		}
	
	
	printf("%.6lf", (double)(n-ans)/n);
	return 0;
}

  

 

 

posted @ 2024-07-18 19:22  cn是大帅哥886  阅读(29)  评论(0)    收藏  举报