我正在做一个练习(自学):“展示如何确定一个有向图 G 是否包含一个通用链接——一个具有入度 (V-1)(V 是顶点数)和出度的顶点——时间为 O(V) 的 0 度,给定 G 的邻接矩阵。我在这里编写了代码:
int UniversalSink(const int *a, int N)
{
int i,j,i1,j1,q;
i=0;
i=0;
q=YES;
j=-1;
do
{
j++;
if (j==N)
break;
while ( (*(a+i*MAX+j)) ==0 )
{
j++;
if (j==N)
{
break;
}
}
if (j==N)
break;
q= YES;
for (; i<j; i++)
if ( (*(a+i*MAX+j)) ==0 )
{
i=j,j=i-1;
q= NO;
break;
}
if (q==NO)
continue;
q=YES;
/*
for (i=0; i<=j; i++ )
if (a[j][i] ==1 )
{
i=j;
q=NO;
ok=NO;
trai = NO;
break;
}
if (q==NO)
continue;
*/
q=YES;
for (i1= j+1; i1<N; i1++)
if ((*(a + i1*MAX +j)) ==0 )
{
i=i1, j=i-1;
q=NO;
break;
}
if (q==NO)
continue;
}
while (j<N);
{
i1=i;
for (j1=0; j1<N;j1++)
if ( (*(a + i1*MAX +j1 )) ==1 )
return -1;
j1=i;
for (i1=0; i1<N;i1++)
{
if (i1==j1)
continue;
if ( (*(a + i1*MAX +j1))==0)
return -1;
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
它需要一个 NN 矩阵并返回通用接收器的位置(如果存在则为 0 到 N-1,如果不存在则为 -1)但是我真的不知道它是否为 O(V),并且在事实上,我不确定它是否会始终计算出所需的结果
(随意评论我的代码的任何其他方面,例如使用太多中断)
lca*_*lov 10
您可以使用以下代码:
int DetectSink(matrix G, int V) {
int i = 0;
int j = 0;
while (i < V && j < V)
if (G[i][j])
i = i + 1;
else j = j + 1;
if (i < V && IsSink(G, i)) return i;
return -1;
}
Run Code Online (Sandbox Code Playgroud)
如果 k 是一个通用汇,那么邻接矩阵 ( G) 的第 k 行将全为 0,第 k 列将全为 1(除了G[k][k] = 0)。
OBS:我们可以得出结论,最多只有一个汇。
如果在 中k存在通用汇G,那么最终我们会得到位置(i = k, j)或(i, j = k)。
k
+---+---+---+---+---+
| | | 1 | | |
+---+---+---+---+---+
| | | 1 | | |
+---+---+---+---+---+
k | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+
| | | 1 | | |
+---+---+---+---+---+
| | | 1 | | |
+---+---+---+---+---+
Run Code Online (Sandbox Code Playgroud)
如果我们到达行 k (j=k)之前的列 k (i=k),我们的算法执行 then 块直到
(i = k, j = k),然后它执行else块直到(i = k, j = V)。在其他情况下,如果第 k 行比第 k 列先到达,则else块会执行到 while 循环的末尾,直到(i = k, j = V)。
最后,我们必须检查是否i是通用汇,因为我们知道汇是否存在i,但我们不知道如果通用汇不存在,我们的算法将做什么G。
运行时间是O(V),因为在每一步中我们都会增加i或j,所以最多发生2V这样的操作。该IsSink部分O(V)。
使用 Divide & Conquer 有一个很好的解决方案:
在这个解决方案中,我们将一组候选对象保留到通用接收器中,并且在每一步中,我们制作顶点对并丢弃两个顶点中的一个,以便分析初始候选对象的一半。