2438: [Zhongshan City Election 2011] Murder Game
Description
A cold-blooded killer sneaked into Na-wiat and pretended to be a civilian. The police want to be in N people.
Find out who the killer is.
The police can verify everyone. If the target of the police is a civilian, he will tell the police that he
Who knows, who is the killer, who is the civilian. If the subject of investigation is a killer, the killer will kill the police.
Now the police know who everyone knows.
Everyone can be a killer, but the probability of seeing them as killers is the same.
Question: According to the optimal situation, the probability of ensuring the police's own safety and knowing who is the killer is the greatest.
Less?
Input
The first line has two integers N and M.
Then there are M lines, two integers x and Y in each line, indicating that x knows y (y does not necessarily know x, for example, Comrade Hu Jintao).
Output
It contains only one real number in a row, and retains six bits behind the decimal point to represent the maximum probability.
Sample Input
1 2
1 3
1 4
1 5
Sample Output
HINT
The police only need to verify 1. If 1 is a killer, the police will be killed. If 1 wasn't a killer, he would tell the police.
Look at 2,3,4,5 who's the killer. The probability of 1 being a killer is 0.2, so it's possible to know who the killer is but not killed.
The rate is 0.8. For 100% of the data, there are 1 < N < 10 0000, 0 < M < 30 0000.
Just touched the tarjan algorithm... It's said that after that some god will give the title of tarjan, orz must say one more sentence when QAQ writes the tarjan function before he writes the train of thought.
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].v;
if (!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if (vis[y])
{
low[x]=min(dfn[y],low[x]);
}
}
This must be paid attention to... We checked out the wrong orz at noon one night. vis records whether it's on the stack, not whether it's traversed, so we need to use dfn to judge, so when vis is 0, this point may have been searched...
At first, when we see the probability, we are very confused, and the examples are comparatively watery, so we turn over dalao's problem to see the explanation below...
Because there are only two possibilities to ask a person, one is the killer, the other is not. So the probability is: (1) the number of inquiries / the total number of inquiries)
Then the maximum probability is required to minimize the number of inquiries. At this point, the idea is obvious, first tarjan reduction point, and then find out the number of points with a zero degree of access (must be asked).
At this time, there is a special case, a point with a degree of 0, which links all points with a degree of more than 1, that is, we really do not need to ask this point to know the answer. So just subtract it.
The code is as follows: ovo
I am still too tm weak orz#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<queue> using namespace std; int read() { int f=1,p=0; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') {p=p*10+c-'0';c=getchar();} return f*p; } struct edge { int next,u,v; }e[300005],nw[300005]; int tot=0,s=0,n,m,sum=0,res=0.0; int st[300005],vis[100005],num[300005],be[300005],head[300005],enter[300005],hd[300005],low[100005],dfn[100005]; void tarjan(int x) { low[x]=dfn[x]=++tot; vis[x]=1; st[++s]=x; for (int i=head[x];i;i=e[i].next) { int y=e[i].v; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if (vis[y]) { low[x]=min(dfn[y],low[x]); } } if (low[x]==dfn[x]) { while (st[s+1]!=x) { num[x]++; be[st[s]]=x; vis[st[s]]=0; s--; } } } int main() { n=read();m=read(); for (int i=1;i<=m;i++) { int u=read(),v=read(); e[i].u=u; e[i].v=v; e[i].next=head[u]; head[u]=i; } for (int i=1;i<=n;i++) { if (!dfn[i]) tarjan(i); } for (int i=1;i<=n;i++) { for (int j=head[i];j;j=e[j].next) if (be[i]!=be[e[j].v]) { ++sum; nw[sum].u=be[i]; nw[sum].v=be[e[j].v]; nw[sum].next=hd[be[i]]; hd[be[i]]=sum; ++enter[be[e[j].v]]; } } for (int i=1;i<=n;i++) { if (!vis[be[i]]&&!enter[be[i]]) { vis[be[i]]=1; res++; } } for (int i=1;i<=n;i++) { if (num[be[i]]==1&&vis[be[i]]) { int flag=0; for (int j=hd[be[i]];j;j=nw[j].next) if (enter[nw[j].v]<=1) {flag=1;break;} if (!flag) {res--;break;} } } double ans=(double)(1.0-(double)(1.0*res/n)); printf("%.6lf",ans); return 0; }