2438: [中山市选2011]杀人游戏
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2815 Solved: 808
[Submit][Status][Discuss]
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
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
数据已加强!
Source
容斥一下,最优的的方式就是去询问那些入度为0的点
那种情况是我们按照这种方式完不成任务的呢,就是入度为0的店是杀手
那么我们先对图进行Tarjan缩一下点,有入度的点,显然我们可以不用直接访问,那么我们访问每个入度为0的点
不过这里有个特殊情况,如果存在一个被搁置的点,他最后是不用访问的比如:3个人ABC,A认识B,那么访问A后,A,B和C的身份都能得知
这样就可以少询问一个,但是注意,这种情况的条件是:
入度为0,且只包含1个点,且这个点指向的SCC的入度>=2(缩点前)【并不仅仅是出入度为0】<-特别容易出错
比如:3个人ABC,A认识B,C认识B,那么访问A或C后都可以得到所有人身份;
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 inline int read(){ 5 int x=0;int f=1;char ch=getchar(); 6 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 7 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 8 return x*f; 9 } 10 const int MAXN=1e6+10; 11 struct node{ 12 int y,next; 13 }e[MAXN],E[MAXN]; 14 int linkk[MAXN],Linkk[MAXN],len,stark[MAXN],n,m,cnt[MAXN],sum[MAXN],dfs_clock=0,top,mark[MAXN],ine[MAXN],tot,vis[MAXN],dfn[MAXN],low[MAXN]; 15 inline void insert(int xx,int yy){ 16 e[++len].y=yy;e[len].next=linkk[xx];linkk[xx]=len; 17 } 18 inline void insertt(int xx,int yy){ 19 E[++len].y=yy;E[len].next=Linkk[xx];Linkk[xx]=len; 20 } 21 inline void tarjin(int st){ 22 dfn[st]=low[st]=++dfs_clock; 23 vis[st]=1;stark[++top]=st; 24 for(int i=linkk[st];i;i=e[i].next){ 25 if(!dfn[e[i].y]){ 26 tarjin(e[i].y); 27 low[st]=min(low[e[i].y],low[st]); 28 } 29 else if(vis[e[i].y]) low[st]=min(low[st],dfn[e[i].y]); 30 } 31 if(dfn[st]==low[st]){ 32 int k;tot++; 33 do{ 34 k=stark[top--]; 35 vis[k]=0; 36 ine[k]=tot; 37 sum[tot]++; 38 }while(k!=st); 39 } 40 } 41 void init(){ 42 n=read();m=read(); 43 for(int i=1;i<=m;i++){ 44 int xx=read();int yy=read(); 45 insert(xx,yy); 46 } 47 } 48 void rebuild(){ 49 len=0; 50 for(int i=1;i<=n;i++){ 51 for(int j=linkk[i];j;j=e[j].next){ 52 if(ine[i]!=ine[e[j].y]&&!mark[ine[e[j].y]]){ 53 cnt[ine[e[j].y]]++;mark[ine[e[j].y]]=1; 54 //cout<<ine[i]<<‘ ‘<<ine[e[j].y]<<endl; 55 insertt(ine[i],ine[e[j].y]); 56 } 57 } 58 for(int j=linkk[i];j;j=e[j].next){ 59 mark[ine[e[j].y]]=0; 60 } 61 } 62 } 63 inline bool dp(int st){ 64 if(cnt[st]!=0||sum[st]!=1) return 0; 65 for(int i=Linkk[st];i;i=E[i].next){ 66 if(cnt[E[i].y]==1) return 0; 67 } 68 return 1; 69 } 70 void solve(){ 71 for(int i=1;i<=n;i++){ 72 if(!dfn[i]) tarjin(i); 73 } 74 rebuild(); 75 int ans=0; 76 for(int i=1;i<=tot;i++){ 77 if(!cnt[i]){ 78 ans++; 79 } 80 } 81 for(int i=1;i<=tot;i++){ 82 if(dp(i)){ 83 ans--;break; 84 } 85 } 86 printf("%lf\n",1.0*(n-ans)/n); 87 } 88 int main(){ 89 init(); 90 solve(); 91 return 0; 92 }