洛谷 4819 [中山市選]殺人遊戲
阿新 • • 發佈:2018-09-04
其他 www. tro answer 快的 https www swe sum
題目戳這裏
Solution
首先我們可以想到,如果某個人沒有任何一個人認識他,那麽警察必須通過調查他獲取他的身份,那麽思路便很清晰了,從所有入度為0的點遍歷,就可以獲得所有人的身份,並且易知這樣的花費也是最少的,但如果這張圖就是一個環呢?那麽不是沒有一個入度為0的點?所以我們需要通過縮點來使這張圖變成DAG,記錄所有入度為0的點除以總點數。
然後...你就會發現只有21分,233。
為什麽呢?舉個栗子:
假設你通過其他的點把整張圖遍歷完了,只剩下一個點,那麽我們還需要對他遍歷嗎?因為只有一個殺手,所以很明顯通過其他人的身份就知道這個人的身份,所以這種情況需要特判。
但這個點滿足什麽條件呢?很明顯不需要它也可以把其他點遍歷完,要麽是他不連接任何點,要麽是它連接的點度數都大於1(通過其他點也可以到達)。這樣就可以愉快的AC了!
PS:數組真的要開大點,很坑!!!
Coding
#include<bits/stdc++.h> using namespace std; const int N = 1e6+10; struct road { int to,next; }e[N*5],edge[N*5]; int n,m,head[N],cnt,u[N],v[N],in[N]; void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } void Readd(int x,int y) { edge[++cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; } int sum,color[N],low[N],ins[N],Time[N],sta[N],top=1,col,num[N]; void Tarjan(int x) { Time[x]=low[x]=++sum; sta[top++]=x; ins[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(ins[v]==0) { Tarjan(v); low[x]=min(low[x],low[v]); } else if(ins[v]==1) low[x]=min(low[x],Time[v]); } if(Time[x]==low[x]) { col++; do { top--; color[sta[top]]=col; ins[sta[top]]=-1; }while(sta[top]!=x); } return ; } int main() { cin>>n>>m; if(n==1) {cout<<"1.000000"; return 0;} if(m==0) {printf("%.6lf",1.0/n); return 0;} for(int i=1;i<=m;i++) { scanf("%d%d",&u[i],&v[i]); add(u[i],v[i]); } for(int i=1;i<=n;i++) if(!ins[i]) Tarjan(i); memset(head,0,sizeof(head)); cnt=0; for(int i=1;i<=n;i++) num[color[i]]++; for(int i=1;i<=m;i++) if(color[u[i]]!=color[v[i]]) Readd(color[u[i]],color[v[i]]),in[color[v[i]]]++; int flag=0,ans=0; for(int x=1;x<=col;x++) { int fuck=1; if(in[x]!=0) continue ; if(num[x]!=1) continue ; for(int i=head[x];i;i=edge[i].next) if(in[edge[i].to]==1) {fuck=0; break ;} if(fuck==1) { flag=1; break ; } } for(int i=1;i<=col;i++) if(in[i]==0) ans++; ans-=flag; double answer=double(n-ans)/double(n); printf("%.6lf",answer); return 0; }
洛谷 4819 [中山市選]殺人遊戲