您的位置:首页 > 其它

6-10 Strongly Connected Components(30 分)

2018-01-15 14:00 337 查看
为了便于测试也写了ReadG()
自己测试没问题,但目前仍无法通过测试样例
怀疑是结构体指针的分配与题目用意不符,
另外孤立点的输入格式不明
Tarjan算法参考修改自: http://blog.csdn.net/qq_34374664/article/details/77488976#
//ReadG()可实现:
//1.顶点序号任意(但需唯一)
//2.顶点输入顺序任意

//ReadG()未实现:
//1.输入顶点的序号的排序//非必要
//2.入度大于零且出度等于零的顶点的确定//二分查找可更快

//ReadG()问题:
//1.PtrToVNode *Array 和 PtrToVNode Next 的分配是否合理?
/*
本程序的分配方法
基于如下的题目定义:
typedef struct VNode *PtrToVNode;
struct VNode {
Vertex Vert;
PtrToVNode Next;
};
typedef struct GNode *Graph;
struct GNode {
int NumOfVertices;
int NumOfEdges;
PtrToVNode *Array;
};//题目定义引用结束
指针分配方法:
1.
Graph graph = (Graph)malloc(sizeof(struct GNode));

2.二级指针 Array 申请连续空间存放 一级指针,
graph->Array =
(PtrToVNode *)malloc(graph->NumOfVertices * sizeof(PtrToVNode));
3.每一个一级指针 Array[i]申请连续空间存放 struct VNode 变量
for(i = 0; i < graph->NumOfVertices; ++i)
graph->Array[i] =
(PtrToVNode)malloc(graph->NumOfVertices * sizeof(struct VNode));
4.至此生成了 NumOfVertices * NumOfVertices 的 邻接表
*/
//2.孤立点(出度为零且入度为零)的输入格式?
/*
基于 Sample Input 格式,
本程序方法是输入
5 -2
确认 5 为孤立点 // 孤立点指向一个不可能的输入点(本程序设定为-2)
*/

//StronglyConnectedComponents函数 使用的是 Tarjan算法
//注意测试用例的最大节点数等于15 超过了 MaxVertices
//

#include <stdio.h>
#include <stdlib.h>
//注意测试用例的最大节点数等于15 超过了 MaxVertices
#define MaxVertices 10  /* maximum number of vertices */
typedef int Vertex;     /* vertices are numbered from 0 to MaxVertices-1 */
typedef struct VNode *PtrToVNode;
struct VNode {
Vertex Vert;
PtrToVNode Next;
};
typedef struct GNode *Graph;
struct GNode {
int NumOfVertices;
int NumOfEdges;
PtrToVNode *Array;
};
Graph ReadG(); /* details omitted */

void PrintV( Vertex V )
{
printf("%d ", V);
}

void StronglyConnectedComponents( Graph G, void (*visit)(Vertex V) );

int main()
{
Graph G = ReadG();
StronglyConnectedComponents( G, PrintV );
return 0;
}

/* Your function will be put here */
void Insert(int a[], int *size, int x)//仅用于ReadG()
{
int i, j;
for(i = 0; i < (*size); ++i){
if(a[i] == x) return;
}
++(*size);
a[(*size)-1] = x;
}

Graph ReadG()
{
Graph graph = (Graph)malloc(sizeof(struct GNode));

scanf("%d %d", &(graph->NumOfVertices), &(graph->NumOfEdges));

if(graph->NumOfVertices > 15){//15 是测试用例中顶点数最大值
return NULL;
}

graph->Array =
(PtrToVNode *)malloc(graph->NumOfVertices * sizeof(PtrToVNode));

int i;
for(i = 0; i < graph->NumOfVertices; ++i)
graph->Array[i] =
(PtrToVNode)malloc(graph->NumOfVertices * sizeof(struct VNode));
//Essential !!!

for(i = 0; i < graph->NumOfVertices; ++i)
{
graph->Array[i]->Vert = -10;//
graph->Array[i]->Next = NULL;
}

if(graph->NumOfEdges == 0 && graph->NumOfVertices > 0)//只有孤立点,顶点序号从零开始
{
for(i = 0; i < graph->NumOfVertices; ++i)
{
graph->Array[i]->Vert = i;
}
return graph;
}

int u, v;
PtrToVNode current, //接收当前输入的临时指针,单链表头插法插入graph->Array[j]
output;
int vert_cnt = 0;//graph->Array[j]->Vert的个数(即起点个数)
int j = 0;
int *a = (int *)malloc(graph->NumOfVertices * sizeof(int));//存放每条边的终点(a[i]不重复),最后和起点比较得出出度为零且入度大于零的顶点
int len_a = 0;//a中元素个数
for(i = 0; i < graph->NumOfVertices; ++i) a[i] = -8;
for(i = 0; i < graph->NumOfEdges; ++i)
{
scanf("%d %d", &u, &v);
if(v == -2){//isolated point
graph->Array[i]->Vert = u;
graph->Array[i]->Next = NULL;//前面初始化过,不写也行
++vert_cnt;
++i;
continue;
}
current = (PtrToVNode)malloc(sizeof(struct VNode));
for(j = 0; j < vert_cnt; ++j)
{
if(u == graph->Array[j]->Vert)
{
break;
}
else continue;
}
if(j == vert_cnt)
{
graph->Array[j]->Vert = u;
++vert_cnt;////
}
current->Vert = v;
current->Next = graph->Array[j]->Next;
graph->Array[j]->Next = current;
Insert(a, &len_a, v);
}
printf("print a[]\n");
for(i = 0; i < len_a; ++i)
{
printf("%d ", a[i]);
}
printf("\nthen initialize the remanent point\n");
//then initialize the remanent point whose outdegree = 0 and indegree > 0
// 存在于a[]且不存在于Array[]的顶点的入度大于零且出度等于零,附加到Array[]后面
int discovered;
for(i = 0; i < len_a; ++i)
{
discovered = 0;
for(j = 0; j < vert_cnt; ++j)
{
if(a[i] == graph->Array[j]->Vert)
{
discovered = 1;
break;
}
}
if(discovered == 0)
{
graph->Array[vert_cnt]->Vert = a[i];
//graph->Array[j]->Next = NULL;
++vert_cnt;
}
}
printf("Input finished.Then try to output the input.\n");
for(i = 0; i < graph->NumOfVertices; ++i)
{
PrintV(graph->Array[i]->Vert);
output = graph->Array[i]->Next;
while(output != NULL)
{
PrintV(output->Vert);
output = output->Next;
}
if(output == NULL)
printf("\n");
}
printf("READG() finished.\n");
return graph;
}

//注意测试用例最大顶点数是 15 ,大于 MaxVertices==10
#define MaxInput 15
Vertex DFN[MaxInput] = {0},
//DFN[]作为这个点搜索的次序编号(时间戳),简单来说就是 第几个被搜索到的。%每个点的时间戳都不一样%。
LOW[MaxInput] = {0},
//作为每个点在这颗树中的,最小的子树的根,每次保证最小,like它的父亲结点的时间戳这种感觉。如果它自己的LOW[]最小,那这个点就应该从新分配,变成这个强连通分量子树的根节点。
//ps:每次找到一个新点,这个点LOW[]=DFN[]
stack[MaxInput] = {0},
access[MaxInput] = {0},
cnt = 0, tot = 0, index = 0;
int min(int x, int y)
{
return (x<y)?x:y;
}
void Tarjan(Graph g, Vertex x, void (*visit)(Vertex V))
{
DFN[x] = LOW[x] = ++tot;
stack[++index] = x;
access[x] = 1;
int i;
PtrToVNode p;
for(i = 0; i < g->NumOfVertices; ++i)
{
if(g->Array[i]->Vert == x)
{
for(p = g->Array[i]->Next; p != NULL; p = p->Next)
{
if(!DFN[p->Vert]){
Tarjan(g, p->Vert, PrintV);

9363
LOW[x] = min(LOW[x], LOW[p->Vert]);
}
else if(access[p->Vert]){
LOW[x] = min(LOW[x], DFN[p->Vert]);
}
}
break;
}

}
if(LOW[x] == DFN[x])
{
do{
PrintV(stack[index]);
access[stack[index]] = 0;
index--;
++cnt;
}while(x != stack[index+1]);
if(cnt != g->NumOfVertices)
printf("\n");
}
}
void StronglyConnectedComponents( Graph G, void (*visit)(Vertex V) )
{
for(int i = 0; i < G->NumOfVertices; ++i)
if(DFN[G->Array[i]->Vert]==0) Tarjan(G, G->Array[i]->Vert, PrintV);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息