题目大意:给出一张有向人物关系图,告诉你谁认识谁,认识具有传递性。其中有一个人是犯人。现在警察要调查谁是犯人。他可以问任何人。但是如果他问到了犯人,那么它就会死。如果他问到的一个人认识犯人,这个人就会告诉警察谁是犯人。问警察保证自身安全并知道犯人是谁的概率最大是多少。
思路:这个题前一阵子重测了,加强了数据,卡掉了网上一片AC代码。。
正解并不是很难想。首先先缩点,整个图变成拓扑图,之后会出现一些类似根的东西,这些scc入度为0,只要警察询问了这些scc每一个中的任意一个,就肯定能知道谁是犯人。安全程度就简单算一下。
但是会有特殊情况。比如只有一个人的情况,警察不用询问就可以知道他肯定是犯人。
类似的,如果在整个图中有一个scc的size为1并且这个scc的出边所到达的scc的入度全部大于1,那么就不用询问这个点,询问所有其他的“根”就能推出这个人是不是犯人。
CODE:
#include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define MAX 3000010 using namespace std; #define min(a,b) ((a) < (b) ? (a):(b)) #define max(a,b) ((a) > (b) ? (a):(b)) int points,edges; int head[MAX],total; int next[MAX],aim[MAX]; inline void Add(int x,int y) { next[++total] = head[x]; aim[total] = y; head[x] = total; } int dfn[MAX],low[MAX],_clock; int stack[MAX],top; bool in_stack[MAX]; int changed[MAX],scc,cnt[MAX]; void Tarjan(int x) { dfn[x] = low[x] = ++_clock; stack[++top] = x; in_stack[x] = true; for(int i = head[x]; i; i = next[i]) { if(!dfn[aim[i]]) Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]); else if(in_stack[aim[i]]) low[x] = min(low[x],dfn[aim[i]]); } if(low[x] == dfn[x]) { scc++; int temp; do { temp = stack[top--]; in_stack[temp] = false; changed[temp] = scc; ++cnt[scc]; }while(temp != x); } } int _in[MAX]; int main() { cin >> points >> edges; for(int x,y,i = 1; i <= edges; ++i) { scanf("%d%d",&x,&y); Add(x,y); } for(int i = 1; i <= points; ++i) if(!dfn[i]) Tarjan(i); for(int x = 1; x <= points; ++x) for(int i = head[x]; i; i = next[i]) if(changed[x] != changed[aim[i]]) ++_in[changed[aim[i]]]; int ans = 0; for(int i = 1; i <= scc; ++i) ans += !_in[i]; bool flag = false; for(int x = 1; x <= points; ++x) { if(cnt[changed[x]] != 1 || _in[changed[x]]) continue; bool temp = true; for(int i = head[x]; i; i = next[i]) if(_in[changed[aim[i]]] == 1) { temp = false; break; } if(temp) { flag = true; break; } } ans -= flag; cout << fixed << setprecision(6) << 1.0 - (double)ans / points << endl; return 0; }
时间: 2024-10-05 13:55:53