ZOJ 2682 People like People(DFS)

来源:互联网 发布:乐谱排版软件 编辑:程序博客网 时间:2024/05/09 04:45

首先进行删点操作.

对于入度为0的点u 删除点u, 将u的邻接点的入度减1,一直删除直到不存在入度为0的点..(保证了每个点都被别人喜欢)

对于出度为0的点u 删除点u,并删除所有连接到点u的点,一直删除直到没有出度为0的点.(保证了每个点都喜欢别人)

然后对(正图和反图合并)进行DFS,找出结点数最多的分量,输出结果.

#include <iostream>#include <cstdio>#include <memory.h>#include <queue>using namespace std;const int maxn = 10001;struct edge{int v, next;}es[maxn * 3], esr[maxn * 3];int head1[maxn], head2[maxn], ind[maxn], oud[maxn], n ,m, cnt;bool vis[maxn], vis2[maxn];void addEdge(edge es[maxn], int head[], int u, int v, int eidx){es[eidx].v = v;es[eidx].next = head[u];head[u] = eidx;}void dfs(int u, int & cnt){cnt++;vis[u] = 1;for (int ne = head1[u]; ne != -1; ne = es[ne].next){int v = es[ne].v;if(!vis[v]){dfs(v, cnt);}}for (int ne = head2[u]; ne != -1; ne = esr[ne].next){int v = esr[ne].v;if(!vis[v]){dfs(v, cnt);}}}int main(){int T;scanf("%d", &T);while (T--){scanf("%d%d", &n, &m);memset(head1, -1, sizeof(head1));memset(head2, -1, sizeof(head2));memset(ind, 0, sizeof(ind));memset(oud, 0, sizeof(oud));memset(vis, 0, sizeof(vis));memset(vis2, 0, sizeof(vis2));int eidx = 0;for (int i = 0; i < m; ++i){int u, q;scanf("%d%d", &u, &q);while (q--){int v;scanf("%d", &v);addEdge(es, head1, u, v, eidx);addEdge(esr, head2, v, u, eidx++);ind[v]++;oud[u]++;}}queue<int>q;for (int i = 1; i <= n; ++i){if(ind[i] == 0){q.push(i);}}while (q.size()){//删除入度为0的点int u = q.front();q.pop();for (int ne = head1[u]; ne != -1; ne = es[ne].next){int v = es[ne].v;if(--ind[v] == 0)q.push(v);}vis[u] = 1;}for (int i = 1; i <= n; ++i){if(oud[i] == 0){q.push(i);}}while (q.size()){//删除出度为0和喜欢它的点int u = q.front();q.pop();vis2[u] = 1;for (int ne = head2[u]; ne != -1; ne = esr[ne].next){int v = esr[ne].v;if(!vis2[v]){vis[v] = 1;q.push(v);}vis[v] = 1;}vis[u] = 1;}int ans = 0;for (int i = 1; i <= n; ++i){if(!vis[i]){int cnt = 0;dfs(i, cnt);ans = max(ans, cnt);}}printf("%d\n",ans);}return 0;}


原创粉丝点击