问题描述
我正在尝试用 C 语言解决一个问题。问题陈述是(阅读整个问题对我的怀疑并不重要):
给定一个由 N 个节点组成的任意无权根树。
该问题的目标是找到树中两个节点之间的最大距离。
两个节点之间的距离是节点之间路径上的边数(任何一对节点之间都会有一条唯一的路径,因为它是一棵树)。
节点将编号为 0 到 N - 1。
树作为数组 A 给出,节点 A[i] 和 i 之间有一条边(0
我创建了 TreeNode 并将所有下一个连接 TreeNode 指针存储在数组中(如图中的邻接列表)
我的解决方案是:
/**
* @input A : Integer array
* @input n1 : Integer array's ( A ) length
*
* @Output Integer
*/
struct TreeNode2 {
int value;
struct TreeNode2 *next;
};
struct TreeNode2* createNode(int n)
{
struct TreeNode2 *node = (struct TreeNode2 *)calloc(1,sizeof(struct TreeNode2));
node->value = n;
node->next = NULL;
return node;
}
int maximum(int a,int b)
{
if(a>b)
return a;
return b;
}
int dfs(struct TreeNode2 **tree,int node)
{
if( tree[node] == NULL )
return 0;
int len1 = 0;
int len2 = 0;
struct TreeNode2 *ptr = tree[node];
while(ptr!=NULL)
{
int curr = dfs(tree,(ptr->value));
if( curr > len1 )
{
len1 = curr;
}
else if(curr > len2)
{
len2 = curr;
}
ptr = ptr->next;
}
return maximum( len1 + len2,maximum( len1,len2 ) + 1 );
}
int solve(int* A,int n1)
{
struct TreeNode2 *tree[n1];
int i=0;
for(i=0;i<n1;i++)
{
tree[i] = NULL;
}
for(i=0;i<n1;i++)
{
if(A[i] != -1)
{
struct TreeNode2 *temp = tree[i];
struct TreeNode2 *newNode = createNode(A[i]);
tree[i] = newNode;
newNode->next = temp;
// printf("A[i] = %d \n",A[i]);
struct TreeNode2 *temp2 = tree[ A[i] ];
struct TreeNode2 *newNode2 = createNode(i);
tree[ A[i] ] = newNode2;
newNode2->next = temp2;
}
}
int ans = dfs(tree,0);
return ans;
}
tree[ A[i] ] = newNode2;
在 forloop 的求解函数中输入 -1,0
。我试过 tree[A[i]] = NULL
(它奏效了)。问题是当 A[i] = 0
、tree[0] = NULL
工作但 tree[0] = newNode2
不工作时,为什么。?
解决方法
从链接中,示例说明显示节点 0 有 三个 [直接] 子节点(节点,1、2、3)。
我可能错了,但我认为一个有效的算法如下:
当我们构建树时,我们记住了最大深度的节点。
树建好后,我们可以遍历它,找到任何一个[叶子]节点的最大深度,该节点不是我们在构建时找到的最大节点。
解决方案是这两个节点的深度之和
这是我为此编写的一些代码。我提交了测试输入,它通过了。
编辑:我已经修改了测试,现在它通过了所有测试,但超出了“效率”测试中的时间限制。
由于 [看似] O(n^2),我的期望也很高,但我想尝试一种不使用“已访问”的非标准方法。
我添加了一些代码来转储可以使用 graphviz
提供给 -DGRAPH
的文本文件。它产生一个输出文件:grf
。要处理此问题,请执行以下操作:
dot -Tsvg < grf > grf.svg
然后,您可以将浏览器指向 grf.svg
文件以显示图表。
无论如何,这是工作但很慢的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#ifndef ROOTLEAF
#define ROOTLEAF 0
#endif
#if ROOTLEAF
#define PTROK(_ptr) (_ptr != NULL)
#else
#define PTROK(_ptr) 1
#endif
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#define nodeshow(_node,_tag) \
do { \
_nodeshow(_node,_tag); \
} while (0)
#ifndef GRAPH
#define GRAPH
#endif
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#define nodeshow(_node,_tag) \
do { \
} while (0)
#endif
#define MAXNODE 40000
#define COUNTOF(_arr) \
(sizeof(_arr) / sizeof(_arr[0]))
typedef struct node node_t;
struct node {
int paridx;
int depth;
node_t *parent;
node_t *next;
node_t *cldhead;
node_t *cldtail;
node_t *leaf;
};
static node_t *root = NULL;
static node_t *lhsbest = NULL;
static node_t *rhsbest = NULL;
static int Acnt = -1;
static node_t nodelist[MAXNODE + 1] = { 0 };
static int soldepth;
static FILE *xfgrf;
static char *
tlsbuf(void)
{
static int bufidx = 0;
static char buf[16][1000];
char *bp;
bp = buf[bufidx];
++bufidx;
bufidx %= 16;
*bp = 0;
return bp;
}
static int
nodenum(node_t *node)
{
if (node != NULL)
return node - nodelist;
else
return -1;
}
static char *
nodexid(node_t *lhs,node_t *rhs)
{
int lhsnum = nodenum(lhs);
int rhsnum = nodenum(rhs);
int tmp;
char *buf;
if (lhsnum > rhsnum) {
tmp = lhsnum;
lhsnum = rhsnum;
rhsnum = tmp;
}
buf = tlsbuf();
sprintf(buf,"%d,%d",lhsnum,rhsnum);
return buf;
}
static void
_nodeshow(node_t *node,const char *tag)
{
#ifdef DEBUG
if (node != NULL) {
dbgprt("nodeshow: %s node=%d paridx=%d depth=%d\n",tag,nodenum(node),node->paridx,node->depth);
}
else
dbgprt("nodeshow: %s null\n",tag);
#endif
}
// newnode -- create new node;
static node_t *
newnode(int idx,node_t *par)
{
node_t *node;
node = &nodelist[idx];
if (par != NULL) {
node->paridx = nodenum(par);
node->depth = par->depth + 1;
}
else
node->paridx = -1;
node->parent = par;
return node;
}
// fastfind -- find node based on i from A[i]
static node_t *
fastfind(int value)
{
node_t *node;
node = &nodelist[value];
nodeshow(node,"fastfind");
return node;
}
// addchild -- attach child node to parent
static void
addchild(node_t *par,node_t *cld)
{
cld->next = par->cldhead;
par->cldhead = cld;
}
int
pathok(node_t *cur)
{
int okay;
if (ROOTLEAF)
okay = (cur != NULL);
else
okay = (cur != NULL) && (cur != root);
return okay;
}
int
pathcost(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost: ENTER lhs=%d rhs=%d xid=%s\n",nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));
cost = 0;
if (lhs == root) {
dbgprt("pathcost: QWKROOT\n");
cost = rhs->depth;
lhs = NULL;
rhs = NULL;
}
while (1) {
if ((lhs == NULL) && (rhs == NULL))
break;
// join at lower level than root
if (lhs == rhs)
break;
#ifdef DEBUG
nodeshow(lhs,"LHS");
nodeshow(rhs,"RHS");
#endif
lhsok = pathok(lhs);
rhsok = pathok(rhs);
if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
//nodeshow(lhs,"LHSDEEP");
if (lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/D cost=%d\n",cost);
lhs = lhs->parent;
}
continue;
}
if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
//nodeshow(lhs,"RHSDEEP");
if (rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/D cost=%d\n",cost);
rhs = rhs->parent;
}
continue;
}
if (PTROK(lhs) && lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/S cost=%d\n",cost);
lhs = lhs->parent;
}
if (PTROK(rhs) && rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/S cost=%d\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost: EXIT cost=%d\n",cost);
return cost;
}
void
search1(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (ROOTLEAF) {
if (rhs != nodelist) {
if (rhs->cldhead != NULL)
continue;
}
}
else {
if (rhs->cldhead != NULL)
continue;
}
nodeshow(rhs,"ISLEAF");
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
lhsbest = NULL;
rhsbest = NULL;
do {
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"LEAFLHS");
for (rhs = lhs->leaf; rhs != NULL; rhs = rhs->leaf) {
curcost = pathcost(lhs,rhs);
if (curcost > bestcost) {
lhsbest = lhs;
nodeshow(lhsbest,"LHSGUD");
rhsbest = rhs;
nodeshow(rhsbest,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"LHSBEST");
nodeshow(rhsbest,"RHSBEST");
soldepth = bestcost;
}
int
pathcost2(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost2: ENTER lhs=%d rhs=%d xid=%s\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost2: EXIT cost=%d\n",cost);
return cost;
}
void
search2(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
int maxdepth = 0;
lhsbest = NULL;
rhsbest = NULL;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (rhs->cldhead != NULL)
continue;
nodeshow(rhs,"ISLEAF");
if (rhs->depth > maxdepth) {
maxdepth = rhs->depth;
rhsbest = rhs;
}
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
do {
bestcost = maxdepth;
lhsbest = leafbase;
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"RHSBEST");
soldepth = bestcost;
}
void
dograph(void)
{
#ifdef GRAPH
int idx;
node_t *cur;
node_t *par;
char *bp;
char buf[100];
xfgrf = fopen("grf","w");
fprintf(xfgrf,"digraph {\n");
for (idx = 0; idx < Acnt; ++idx) {
cur = &nodelist[idx];
bp = buf;
bp += sprintf(bp,"label=\"N%d D%d\"",nodenum(cur),cur->depth);
if (cur == rhsbest)
bp += sprintf(bp," color=Green");
if (cur == lhsbest)
bp += sprintf(bp," color=Red");
fprintf(xfgrf,"\tN%d [%s]\n",buf);
par = cur->parent;
if (par != NULL)
fprintf(xfgrf,"\tN%d -> N%d\n",nodenum(par),nodenum(cur));
}
fprintf(xfgrf,"}\n");
fclose(xfgrf);
#endif
}
int
solve(int *A,int argcnt)
{
int idx;
int parval;
node_t *par;
if (root != NULL) {
memset(nodelist,sizeof(nodelist));
root = NULL;
}
// find the root node
// FIXME/CAE -- probably always the first
Acnt = argcnt;
for (idx = 0; idx < Acnt; ++idx) {
int parval = A[idx];
if (parval == -1) {
dbgprt("solve: ROOT idx=%d\n",idx);
root = newnode(idx,NULL);
break;
}
}
// build all child nodes:
for (idx = 0; idx < Acnt; ++idx) {
parval = A[idx];
if (parval == -1)
continue;
dbgprt("solve: NODE idx=%d parval=%d\n",idx,parval);
// find parent
par = fastfind(parval);
// create node
node_t *cur = newnode(idx,par);
// attach child to parent
addchild(par,cur);
}
// traverse all nodes in the tree to find max distance ...
search2();
dograph();
return soldepth;
}
,
最后我发现了这个问题,实际上在这个问题树中,连接是无向的,所以代码卡在了 dfs 的循环中。我使用了访问数组来解决这个问题。