【题解】洛谷P2812 校园网络
这个题大概是不难的 _(:3 」∠)_
原题 洛谷P2812
题面概括
有一张有向图,给出点的数量n以及边的数量m,有两个问题:
problem1
至少选几个点开始搜索才能使整个图都能被遍历到
problem2
至少需要添加几条边能使整个图成为一个环?
题目分析
这个题的难点在于,我们不知道连接哪两座学校才能使整个图成为一个环,那么我们可以先把一些小问题完成再去看大问题(佛系)
一、tarjan缩点
从题目可以得知如果这个图中有环,那这个环中若有至少一个点可以被共享,整个环就可以被共享,这就可以把一个环看做成一个点,可以用tarjan缩点完成
二、对入度为0的点和出度为0的点进行操作
子问题1:入度为0的点
如果在所有入度为0的点上设母机,那么整个图都会被共享
这也是problem1的答案
然后我们可以知道,缩点后的图是一个有向无环图,每个点都有一个入度和出度,入度为0的点无法被共享,那我们要想办法让这种点入度不为0呐~肯定要连边使入度为0的点的入度不为0(好绕)
子问题2:出度为0的点
这样的话问题又来了:如果随便找个点连接入度为0的点的话,那连接入度为0的那个点的出度是否为0?
如果出度不为0,那么从这个点出发的点就无法在这个环里,以它为母机,会有学校共享不到,所以出度为零的点也需要向外连一条边
分析结果
不难想到,让出度为0的点向入度为0的点连一条边
那答案就出来了:
problem1:
入度为0的点的个数
problem2:
max(入度为0的点的数量,出度为0的点的数量):
注意:当只有一个点(或者强连通分量时),输出0!!!(这个可能会成为强化数据)(本人代码里没写~)
更详细的请见完整代码:
#include <iostream> #include <cstdio> #include <cmath> #define MAXN 10010 using namespace std; int vis[MAXN], head[MAXN]; int js = 0, n, m, op=0, cnt, top=0; int sta[MAXN], low[MAXN], dfn[MAXN]; int num[MAXN], sum[MAXN], g=0, oq=0;//num[i]记录点i的序号,sum[i]记录序号为i的强连通分量的元素个数 int rd[MAXN],cd[MAXN];//记录入度和出度 struct edge{ int v, nxt; }e[5000010 << 1]; void addage(int u, int v){ e[++js].v = v; e[js].nxt = head[u]; head[u] = js; } void tarjan(int t){//tarjan缩点板子 sta[++top] = t; vis[t] = 1; low[t] = dfn[t] = ++op; for (int j = head[t]; j; j = e[j].nxt){ int v = e[j].v; if (!dfn[v]){ tarjan(v); low[t] = min (low[t], low[v]); } else if (vis[v]) low[t] = min (low[t], low[v]); } if (low[t] == dfn[t]){ int f = sta[top--]; vis[f] = 0; num[f] = ++g; sum[g]++; while (f != t){ f = sta[top--]; vis[f] = 0; num[f] = g; sum[g]++; } } } int main(){ int x, y, v, ans=0, jss=0,mm; scanf("%d", &n); for (int i = 1; i <= n; i++){ while (scanf("%d", &x)){ if (x == 0) break; addage(i, x); } }//输入 for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (int i = 1; i <= n; i++){ for (int j = head[i]; j; j = e[j].nxt){ v = e[j].v; if (num[i] != num[v]){ cd[num[i]]++;//记录每个点的入度 rd[num[v]]++;//记录每个点的出度 } } } for (int i = 1;i <= g; i++){ if (!rd[i]){ ans++; }//记录入度为0的点的数量 if (!cd[i]){ jss++; }//记录出度为0的点的数量 } mm=max(ans,jss);//比较 printf("%d\n%d\n",ans,mm); return 0; }
大概是这个亚子啦~~
PS:窝已经在洛谷发了*★,°*:.☆\( ̄▽ ̄)/$:*.°★*