[BZOJ 2438] 中山市選2011 殺人遊戲
阿新 • • 發佈:2018-06-09
next include IT top graph pair back -c scanf
。
[BZOJ 2438] 中山市選2011 殺人遊戲
<題目鏈接>
AZe 問的題目,上手發現確實好題 qwq。
如何求出題目要求的概率?
根據題目描述,我們知道,警察調查未知身份者就有可能會死亡,所以查的人越少越安全。
因此,安全查出必須調查的未知身份者數總人數 \(P_{安全查出} = 1 -\frac{必須調查的未知身份者數}{總人數}\)。
如果有一群人,他們直接或間接認識,那麽他們可以看作一個點。
於是想到 Tarjan 求 SCC,縮點建新圖(原因過後交代)。
查一個點,這個點認識的點,都可以明確身份。
所以,查所有新圖上入度為 \(0\) 的點即可,數出個數 \(\mathrm{ans}\)
特殊情況如下:如果有一個人 \(x\) 被孤立,即,\(x\) 所在的 SCC \(\mathrm{size}\) 為 \(1\),且 \(x\) 認識的每個人都不僅僅被 \(x\) 認識(判斷這步需要在新圖上遍歷 \(x\) 所在點的鄰接點,所以需要建新圖),這時候不需要詢問 \(x\) 便可以確定其身份。這時候需 --\(\mathrm{ans}\)。
答案即 \(1 - \frac{ans}{n}\)。
#include <algorithm>
#include <cstdio>
#include <set>
#include <stack>
const int MAXN=100010;
int n,m;
class Graph
{
private:
int V;
public:
Graph(int n)
{
V=n;
for(int i=1;i<=V;++i)
head[i]=nullptr;
}
~Graph(void)
{
for(int i=1;i<=V;++i)
delete head[i];
}
struct Edge
{
int to;
Edge *next;
Edge(int to,Edge* next):to(to),next(next){}
~Edge(void)
{
if(next!=nullptr)
delete next;
}
}*head[MAXN];
void AddEdge(int u,int v)
{
head[u]=new Edge(v,head[u]);
}
}*G1,*G2;
namespace Tarjan
{
bool exist[MAXN];
int cnt,sum,ans,DFN[MAXN],low[MAXN],SCC[MAXN],size[MAXN],in[MAXN];
std::set<std::pair<int,int> > S;
std::stack<int> st;
void DFS(int u)
{
st.push(u);
exist[u]=true;
DFN[u]=low[u]=++cnt;
for(Graph::Edge *i=G1->head[u];i!=nullptr;i=i->next)
{
int v=i->to;
if(!DFN[v])
{
DFS(v);
low[u]=std::min(low[u],low[v]);
}
else if(exist[v])
low[u]=std::min(low[u],DFN[v]);
}
if(DFN[u]==low[u])
{
++sum;
for(int v=0;u^v;)
{
exist[v=st.top()]=false;
st.pop();
++size[SCC[v]=sum];
}
}
}
void Contract(void)
{
for(int u=1;u<=n;++u)
for(Graph::Edge *i=G1->head[u];i!=nullptr;i=i->next)
{
int v=i->to;
if(SCC[u]^SCC[v] && !S.count(std::make_pair(SCC[u],SCC[v])))
{
++in[SCC[v]];
G2->AddEdge(SCC[u],SCC[v]);
S.insert(std::make_pair(SCC[u],SCC[v]));
}
}
}
bool Judge(int u)
{
if(in[u] || size[u]!=1)
return false;
for(Graph::Edge *i=G2->head[u];i!=nullptr;i=i->next)
if(in[i->to]==1)
return false;
return true;
}
void Run(void)
{
for(int i=1;i<=n;++i)
if(!DFN[i])
DFS(i);
G2=new Graph(sum);
Contract();
for(int i=1;i<=sum;++i)
if(!in[i])
++ans;
for(int i=1;i<=sum;++i)
if(Judge(i))
{
--ans;
break;
}
printf("%.6lf\n",(double)(n-ans)/n);
}
}
int main(int argc,char** argv)
{
scanf("%d %d",&n,&m);
G1=new Graph(n);
for(int i=1,x,y;i<=m;++i)
{
scanf("%d %d",&x,&y);
G1->AddEdge(x,y);
}
Tarjan::Run();
return 0;
}
謝謝閱讀。
[BZOJ 2438] 中山市選2011 殺人遊戲