Loj10094 消息的传递
题目描述
我们的郭嘉大大在曹操这过得逍遥自在,但是有一天曹操给了他一个任务,在建邺城内有 NNN 个袁绍的奸细,将他们从 111 到 NNN 进行编号,同时他们之间存在一种传递关系,即若Ci,j=1C_{i,j}=1Ci,j=1,则奸细 iii 能将消息直接传递给奸细 jjj。
现在曹操要发布一个假消息,需要传达给所有奸细,而我们的郭嘉大大则需要传递给尽量少的奸细使所有的奸细都知道这一个消息,问我们至少要传给几个奸细?
输入格式
文件的第一行为 NNN,第二行至第 N+1N+1N+1 行为 N×NN \times NN×N 的矩阵(若第 III 行第 JJJ 列为 111,则奸细 III 能将消息直接传递给奸细 JJJ,若第 III 行第 JJJ 列为 000,则奸细 III 不能将消息直接传递给奸细 JJJ)。
输出格式
输出文件只有一行:即我们的郭嘉大大首先至少要传递的奸细个数。
这题为什么用邻接矩阵输入。。。。
我们可以把整个图用Tarjan缩点,保证每个联通分量内所得的奸细只要有一个人得到,那么所有人得到。
再将缩好的点求一下入度,入度为0的说明是需要传递的。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cstring> #include <stack> #define in(a) a=read() #define REP(i,k,n) for(int i=k;i<=n;i++) #define MAXN 2000010 using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } int n,a,ans,num; int total,head[MAXN],to[MAXN],nxt[MAXN]; int low[MAXN],bel[MAXN],dfn[MAXN],cnt,vis[MAXN],indu[MAXN]; inline void adl(int a,int b){ total++; to[total]=b; nxt[total]=head[a]; head[a]=total; return ; } stack <int> S; inline void Tarjan(int u){ low[u]=dfn[u]=++cnt; S.push(u); vis[u]=1; for(int e=head[u];e;e=nxt[e]){ if(!dfn[to[e]]){ Tarjan(to[e]); low[u]=min(low[u],low[to[e]]); } else if(vis[to[e]]) low[u]=min(low[u],dfn[to[e]]); } if(low[u]==dfn[u]){ num++; while(!S.empty() && S.top()!=u) bel[S.top()]=num,vis[S.top()]=0,S.pop(); if(!S.empty()) bel[S.top()]=num,vis[S.top()]=0,S.pop(); } return ; } int main(){ in(n); REP(i,1,n) REP(j,1,n){ in(a); if(a) adl(i,j); } REP(i,1,n) if(!dfn[i]) Tarjan(i); REP(u,1,n) for(int e=head[u];e;e=nxt[e]) if(bel[u]!=bel[to[e]]) indu[bel[to[e]]]++; REP(i,1,num) if(!indu[i]) ans++; cout<<ans; }