Is this figure connected?
c99 -- 620ish neccessary characters
#include <stdlib.h>
#define S return
typedef struct n N;struct n{int x,y;N*n;};
N*I(int x,int y,N*l){if(!l)goto z;N*m=l;do{if((m->x==x)&&(m->y==y))
S m;m=m->n;}while(m!=l);z:S NULL;}N*A(N*n,N*l){if(!l)n->n=n,l=n;
else n->n=l->n,l->n=n;S l;}N*R(N*n,N*l){if(!l||(l==n&&n->n==n))goto z;
N*m=l;do{if(m->n==n){m->n=n->n;S m;}m=m->n;}while(m!=l);z:S NULL;}
int E(N*l){int i=0;if(!l)goto z;N*m=l;do{++i;m=m->n;}while(m!=l);z:S i;}
int C(N*l){N*c=NULL,*n=l,*m=l=R(n,l);c=A(n,c);int a=E(l)*E(l);do{
if(!l)S 1;n=m->n;if(I(m->x-1,m->y,c)||I(m->x+1,m->y,c)||I(m->x,m->y-1,c)
||I(m->x,m->y+1,c))l=R(m,l),c=A(m,c);m=n;}while(--a);S 0;}
More than half the bulk is taken up by a minimal implementation of a linked list---c is horribly deficient in that sense.
The code here includes the definition of the nodes and all the list manipulation functions called by C
, my connectedness checker.
The method is to maintain two lists (one of connected nodes initialized by the first node) and one of yet-to-be-connected nodes (starting with everything else). What follows is an exhaustive cyclic search to find a connection for each node in turn. There is an upper limit on the number of attempts conservatively set to length-of-the-list squared, which marks the end of attempts. Very inefficient, but functional.
It completes several simple cases of my own devising and both of the given test cases correctly.
Full program with test scaffold and some comments
#include <stdio.h>
#include <stdlib.h>
typedef struct n N;
struct n{
int x,y;
N*n;
};
N*I(int x,int y,N*l){ /* Return pointer to node x,y in l or NULL */
if(!l)goto z;
N*m=l;
do{
if((m->x==x)&&(m->y==y)){
return m;
}
m=m->n;
}while(m!=l);
z:return NULL;
};
N*A(N*n,N*l){ /* Add node n to list l. Return the new l */
if(!l){
n->n=n;
l=n;
}else{
n->n=l->n;
l->n=n;
}
return l;
};
N*R(N*n,N*l){ /* Remove node n from list l. Return the new l */
if(!l||(l==n&&n->n==n))goto z;
N*m=l;
do{
if(m->n==n){m->n=n->n; return m;}
m=m->n;
}while(m!=l);
z:return NULL;
}
int E(N*l){ /* Return the Enumberation of nodes in list l */
int i=0;
if(!l)goto z;
N*m=l;
do{++i;m=m->n;}while(m!=l);
z:return i;
}
int C(N*l){ /* return true if all nodes in list l are connected */
N*c=NULL,*n=l,*m=l=R(n,l); /* put the first node in the connected
list, and mark the start of the
working list */
c=A(n,c);
int a=E(l)*E(l); /* maximum number of times to try to place nodes */
do {
if (!l) return 1; /* when l is empty: we win! */
n=m->n;
if ( I(m->x-1,m->y ,c) ||
I(m->x+1,m->y ,c) ||
I(m->x ,m->y-1,c) ||
I(m->x ,m->y+1,c) ) l=R(m,l), c=A(m,c);
m=n;
} while (--a);
return 0;
}
void P(N*l){ /* Print the list */
printf("List: [");
if(!l)goto z;
N*m=l;
do{printf(" (%d, %d)",m->x,m->y);m=m->n;}while(m!=l);
z:printf(" ]\n");
}
N*G(int x,int y){ /* generate a new node with (x, y) */
N*n;
if(n=malloc(sizeof(N)))n->x=x,n->y=y;
return n;
}
int main(){
N*n,*l=NULL;
n=G(0,0); l=A(n,l);
n=G(1,0); l=A(n,l);
n=G(2,0); l=A(n,l);
n=G(0,1); l=A(n,l);
n=G(0,2); l=A(n,l);
n=G(2,2); l=A(n,l);
n=G(3,2); l=A(n,l);
n=G(4,2); l=A(n,l);
n=G(0,3); l=A(n,l);
n=G(4,3); l=A(n,l);
n=G(0,4); l=A(n,l);
n=G(1,4); l=A(n,l);
n=G(2,4); l=A(n,l);
n=G(4,4); l=A(n,l);
n=G(4,5); l=A(n,l);
n=G(2,6); l=A(n,l);
n=G(3,6); l=A(n,l);
n=G(4,6); l=A(n,l);
P(l);
if (C(l)) {
printf("Connected!\n");
} else {
printf("Not connected.\n");
};
}
My first python version (loosely) translated into golfscript. Urgh. 80 chars.
{1$!!1$!!&{(~:v;:u;[1u+v u 1v+u 1- v u v 1-]2/@.@&.@\-\@|g}{;!}if}:g;{([.;]g}:f;
test cases:
# test cases
[[0 0] [1 0] [2 0] [3 0] [3 1] [3 2] [2 2] [1 2] [0 2] [0 3] [0 4] [1 4] [2 4] [3 4]]:a0;
[[0 0] [1 0] [2 0] [0 1] [0 2] [2 2] [3 2] [4 2] [0 3] [4 3] [0 4] [1 4] [2 4] [4 4] [4 5] [2 6] [3 6] [4 6]]:a1;
a0 f p
a1 f p
python 2.6; second attempt
def f(a):
a = set(a)
e = lambda (x, y) : set([(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)])
p = lambda k : a.discard(k) or map(p, e(k) & a)
p(a.pop())
return not a
python 2.6; first attempt
def f(a):
a = set(a)
e = lambda (x, y) : set([(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)])
b = set([a.pop()])
while b and a:
c = a & e(b.pop())
a -= c
b |= c
return not a
usage:
a_0 = [
(0,0),(1,0),(2,0),(3,0),(3,1),(3,2),(2,2),
(1,2),(0,2),(0,3),(0,4),(1,4),(2,4),(3,4)
]
a_1 = [
(0,0),(1,0),(2,0),(0,1),(0,2),(2,2),(3,2),(4,2),(0,3),
(4,3),(0,4),(1,4),(2,4),(4,4),(4,5),(2,6),(3,6),(4,6)
]
for a in (a_0, a_1):
print 'YES' if f(a) else 'NO'
Perl, 130 133
A simple mark-and-sweep depth-first traversal, made much longer than I'd like by Perl sigils.
sub g{my($a,$b)=@_;g($a-1,$b),g(
$a+1,$b),g($a,$b-1),g($a,$b+1)if
delete$m{$a,$b}}sub f{($a,$b)=@_;
$m{pop,pop}++while@_;g$a,$b;!%m}
Sample use:
say f( (0,0),(1,0),(2,0),(3,0),(3,1),(3,2),(2,2),
(1,2),(0,2),(0,3),(0,4),(1,4),(2,4),(3,4) )
? 'YES' : 'NO';
say f( (0,0),(1,0),(2,0),(0,1),(0,2),(2,2),(3,2),(4,2),(0,3),
(4,3),(0,4),(1,4),(2,4),(4,4),(4,5),(2,6),(3,6),(4,6) )
? 'YES' : 'NO';