原题
https://hihocoder.com/problemset/problem/1174
输入
第1行:1个整数T,表示数据的组数T(1 <= T <= 5)
接下来T组数据按照以下格式:
第1行:2个整数,N,M。N表示课程总数量,课程编号为1…N。M表示顺序关系的数量。1 <= N <= 100,000. 1 <= M <= 500,000
第2…M+1行:每行2个整数,A,B。表示课程A是课程B的前置课程。
输出
第1…T行:每行1个字符串,若该组信息无误,输出"Correct",若该组信息有误,输出"Wrong"。
我的想法
邻接表存储有向图,然后在有向图中查找有无环存在。有些东西已不太熟,能想到的找环就是递归遍历看是否有重复节点,忒繁琐。
解析与思考
- 计算每一个点的入度值deg[i],这一步需要扫描所有点和边,复杂度O(N+M)。
- 把入度为0的点加入队列Q中,当然有可能存在多个入度为0的点,同时它们之间也不会存在连接关系,所以按照任意顺序加入Q都是可以的。
- 从Q中取出一个点p。对于每一个未删除且与p相连的点q,deg[q] = deg[q] - 1;如果deg[q]==0,把q加入Q。
- 不断重复第3步,直到Q为空。
最后剩下的未被删除的点,也就是组成环的点了。在这个过程中,需要注意对于有向图的构建,宜采用邻接表形式,以应对数据量大时的内存溢出问题。
常见的邻接表大多是使用的指针来进行元素的串联,其实我们可以通过数组来模拟这一过程。
int head[ MAXN + 1] = {0}; // 表示头指针,初始化为0
int p[ MAXM + 1]; // 表示指向的节点
int next[ MAXM + 1] = {0}; // 模拟指针,初始化为0
int edgecnt; // 记录边的数量
void addedge(int u, int v) { // 添加边(u,v)
++edgecnt;
p[ edgecnt ] = v;
next[ edgecnt ] = head[u];
head[u] = edgecnt;
}
// 枚举边的过程,u为起始点
for (int i = head[u]; i; i = next[i]) {
v = p[i];
...
}
看了解析之后的解答
#include <iostream>
#include <queue>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define MAXN 100000
#define MAXM 500000
int main(int argc, char** argv) {
int t = 0;
int n = 0;
int m = 0;
std::queue<int> Q;
scanf("%d", &t);
while(t--) {
int head[ MAXN + 1] = {0}; // 表示头指针,初始化为0
int p[ MAXM + 1]; // 表示指向的节点
int next[ MAXM + 1] = {0}; // 模拟指针,初始化为0
int edgecnt = 0; // 记录边的数量
int deg[MAXN + 1] = {0}; // 记录每个点的入度值
scanf("%d %d", &n, &m);
int u, v;
while(m--) {
scanf("%d %d", &u, &v);
++edgecnt;
p[ edgecnt ] = v;
next[ edgecnt ] = head[u];
head[u] = edgecnt;
}
//计算每一个点的入度值deg[i],这一步需要扫描所有点和边,复杂度O(N+M)。
// 枚举边的过程,u为起始点
for (u=1; u <= n; u++) {
for (int i = head[u]; i; i = next[i]) {
v = p[i];
deg[v]++;
}
}
// 把入度为0的点加入队列Q中,当然有可能存在多个入度为0的点,同时它们之间也不会存在连接关系,所以按照任意顺序加入Q都是可以的。
for (int i = 1; i <= n; i++) {
if (deg[i] == 0) {
Q.push(i);
}
}
int left = n;
// 从Q中取出一个点p。对于每一个未删除且与p相连的点q,deg[q] = deg[q] - 1;如果deg[q]==0,把q加入Q。
// 不断重复第3步,直到Q为空。
while (!Q.empty()) {
int temp = Q.front();
Q.pop();
left--;
for (int i = head[temp]; i; i = next[i]) {
v = p[i];
deg[v]--;
if (deg[v] == 0) {
Q.push(v);
}
}
}
if (left > 0) {
printf("Wrong\n");
}
else {
printf("Correct\n");
}
}
}