I've attended this challenge and although I've reached a not too shabby ranking of 167# out of 1628, I remain unsatisfied by my second exercise perfomance managing only to pass 54% of all unit tests.
This is a classic backtracking exercise on an oriented graph where one has to link node to each other depending on node valuation.
1. Graph is oriented and link can only be made to the closest right neighbour or the closest bottom neighbour.
2. Only up to 2 links can connect two nodes.
.
The simplest solution that I think of is to brute force all available possibility for each node in a recursive manner.
3. There are 2 additionnals conditions :
At first these conditions seems hard to enforce, but by looking closely it's not that hard to implement.
. Goin*g downward already ensured that no vertical link can cross an already created horizontal link.
The second condition is enforced by removing solutions that are not fully connected graphs. This seems expensive if one has to verify that every node is connected to every other node. There is a much simpler way : take a node, browse through all the connected neighbours (right and bottom but also top and left) and mark them as browsed. After having marked all reachable nodes, look for unmarked nodes => if any then our graph is not fully connected.
I've reworked on my solution and finally reached 100% for the second exercise.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int getRight(int x,int y,int width,int height,char * grid) {
for (int i = x + 1;i < width;i++) {
if ((grid[i+y*width] >= '0')&&(grid[i+y*width] <= '8')){
return i;
}
}
return -1;
}
int getBottom(int x,int y,int width,int height,char * grid) {
for (int j = y + 1;j < height;j++) {
if ((grid[x+j*width] >= '0')&&(grid[x+j*width] <= '8')){
return j;
}
}
return -1;
}
typedef struct {
int xr;
int yr;
int xb;
int yb;
int counter;
int mark;
int lr;
int lb;
} t_n;
t_n getNmap(t_n * nmap, int width,int height, int x, int y) {
return nmap[x+y*width];
}
int addLinkR(int i, int j, t_n * nmap, int width,int height);
int addLinkL(int i, int j, t_n * nmap, int width,int height);
int apply_ope(t_n * nmap,int width,int height, int x, int y,int ope) {
switch (ope) {
case 0 : // 0/0
if (getNmap(nmap,width,height,x,y).counter == 0) {
return 1;
} else {
return 0;
}
case 1 : // 0/1
if ((getNmap(nmap,width,height,x,y).counter == 1)&&addLinkR(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 2 : // 0/2
if ((getNmap(nmap,width,height,x,y).counter == 2)&&addLinkR(x, y, nmap, width, height)&&addLinkR(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 3 :// 1/1
if ((getNmap(nmap,width,height,x,y).counter == 2)&&addLinkR(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 4 :// 1/2
if ((getNmap(nmap,width,height,x,y).counter == 3)&&addLinkR(x, y, nmap, width, height)&&addLinkR(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 5 :// 2/2
if ((getNmap(nmap,width,height,x,y).counter == 4)&&addLinkR(x, y, nmap, width, height)&&addLinkR(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 6 :// 2/1
if ((getNmap(nmap,width,height,x,y).counter == 3)&&addLinkR(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 7 :// 2/0
if ((getNmap(nmap,width,height,x,y).counter == 2)&&addLinkL(x, y, nmap, width, height)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
case 8 :// 1/0
if ((getNmap(nmap,width,height,x,y).counter == 1)&&addLinkL(x, y, nmap, width, height)) {
return 1;
} else {
return 0;
}
default :
return 0;
}
}
int checkOverlapR(t_n * nmap, int width,int height,int x,int y,int x2, int y2) {
for (int i = 0;i < x+y*width;i++) {
if (nmap[i].lb > 0
&& x < (i%width)
&& x2 > (i%width)
&& y > (i/width) && y < nmap[i].yb) {
return 1;
}
}
return 0;
}
t_n * clone_nmap(t_n * nmap, int width,int height){
t_n * nmapd = (t_n*)malloc(sizeof(t_n)*width*height);
if (nmapd == 0) {
puts("clone_nmap : out of memory !\n");
}
memcpy(nmapd,nmap,sizeof(t_n)*width*height);
return nmapd;
}
void mark_cell(t_n * nmap,int width,int height, int x,int y) {
if (nmap[x+y*width].mark == 1) {
return;
}
nmap[x+y*width].mark = 1;
if ((nmap[x+y*width].xb != -1)&&(nmap[x+y*width].lb > 0)) {
mark_cell(nmap,width,height,nmap[x+y*width].xb,nmap[x+y*width].yb);
}
if ((nmap[x+y*width].xr != -1)&&(nmap[x+y*width].lr > 0)) {
mark_cell(nmap,width,height,nmap[x+y*width].xr,nmap[x+y*width].yr);
}
for (int i = 0;i < x+y*width;i++) {
if (((nmap[i].xb == x)&&(nmap[i].yb == y)&&(nmap[i].lb > 0))||((nmap[i].xr == x)&&(nmap[i].yr == y)&&(nmap[i].lr > 0))) {
mark_cell(nmap,width,height,i%width,i/width);
}
}
}
void mark_connected(t_n * nmap, int width,int height) {
int start = 0;
for (int i = 0;i < width*height;i++) {
if (nmap[i].mark != -1) {
start = i;
break;
}
}
mark_cell(nmap, width, height, start%width,start/width);
}
int check_connected(t_n * nmap, int width,int height) {
for (int i = 0;i < width*height;i++) {
if (nmap[i].mark != -1) {
nmap[i].mark = 0;
}
}
mark_connected(nmap,width,height);
for (int i = 0;i < width*height;i++) {
if (nmap[i].mark == 0) {
return 0;
}
}
return 1;
}
void browse_node(t_n * nmap,int pos, int width,int height) {
if (pos == (width*height-1)&&checkNmap(nmap,width,height)){
if (check_connected(nmap,width,height)) {
displayNmap(nmap,width,height);
exit(0);
} else {
return;
}
}
for (int j = 0;j < 9;j++) {
t_n * nmaptmp = clone_nmap(nmap,width,height);
if (apply_ope(nmaptmp,width,height, pos%width, pos/width,j)) {
browse_node(nmaptmp,pos+1,width,height);
}
free(nmaptmp);
}
}
int addLinkR(int i, int j, t_n * nmap, int width,int height) {
t_n current= getNmap(nmap,width,height,i,j);
if ((current.counter > 0)&&(current.lr < 2)&&(current.xr!=-1)&&(current.yr!=-1)) {
if ((getNmap(nmap,width,height,current.xr,current.yr).counter > 0) &&(!checkOverlapR(nmap,width,height,i,j,current.xr, current.yr))) {
nmap[i+j*width].counter--;
nmap[i+j*width].lr++;
nmap[current.xr+current.yr*width].counter--;;
return 1;
}
}
return 0;
}
int addLinkL(int i, int j, t_n * nmap, int width,int height) {
t_n current= getNmap(nmap,width,height,i,j);
if ((current.counter > 0)&&(current.lb < 2)&&(current.xb!=-1)&&(current.yb!=-1)) {
if (getNmap(nmap,width,height,current.xb,current.yb).counter > 0) {
nmap[i+j*width].counter--;
nmap[i+j*width].lb++;
nmap[current.xb+current.yb*width].counter--;
return 1;
}
}
return 0;
}
int checkNmap(t_n * nmap, int width,int height) {
for (int i = 0;i < width * height;i++) {
if (nmap[i].counter > 0){
return 0;
}
}
return 1;
}
void displayNmap(t_n * nmap, int width,int height) {
for (int i = 0;i < width;i++) {
for (int j = 0;j < height;j++) {
t_n current = getNmap(nmap,width,height,i,j);
if (current.lr > 0) {
printf("%d %d %d %d %d\n",i,j,current.xr,current.yr,current.lr);
}
if (current.lb > 0) {
printf("%d %d %d %d %d\n",i,j,current.xb,current.yb,current.lb);
}
}
}
}
int main()
{
int width; // the number of cells on the X axis
scanf("%d", &width); fgetc(stdin);
int height; // the number of cells on the Y axis
scanf("%d", &height); fgetc(stdin);
char * grid = (char*)malloc(sizeof(char)*width*height);
char * line = (char*)malloc(sizeof(char)*(width+1));
t_n * nmap = (t_n*)malloc(sizeof(t_n)*width*height);
for (int i = 0; i < height; i++) {
fgets(line,31,stdin); // width characters, each either 0 or .
for (int j = 0;j < width;j++) {
grid[j+i*width] = line[j];
}
}
fprintf(stderr,"width=%d\n",width);
fprintf(stderr,"height=%d\n",height);
for (int i = 0; i < height; i++) {
fprintf(stderr,"[");
for (int j = 0;j < width;j++) {
fprintf(stderr,"%c",grid[j+i*width]);
}
fprintf(stderr,"]\n");
}
for (int i = 0; i < width; i++) {
for (int j = 0;j < height;j++) {
nmap[i+j*width].lb = 0;
nmap[i+j*width].lr = 0;
nmap[i+j*width].counter = 0;
nmap[i+j*width].mark = -1;
nmap[i+j*width].xr = -1;
nmap[i+j*width].yr = -1;
nmap[i+j*width].xb = -1;
nmap[i+j*width].yb = -1;
if ((grid[i+j*width] >= '0')&&(grid[i+j*width] <= '8')) {
int xr = getRight(i,j,width,height,grid);
int yr = xr == -1 ? -1 : j;
int yb = getBottom(i,j,width,height,grid);
int xb = yb == -1 ? -1 : i;
nmap[i+j*width].mark = 0;
nmap[i+j*width].xr = xr;
nmap[i+j*width].yr = yr;
nmap[i+j*width].xb = xb;
nmap[i+j*width].yb = yb;
nmap[i+j*width].lb = 0;
nmap[i+j*width].lr = 0;
char s[2];
s[0] = grid[i+j*width];
s[1] = 0;
nmap[i+j*width].counter = atoi(s);
}
}
}
browse_node(nmap,0,width,height);
free(grid);
free(line);
free(nmap);
fprintf(stderr,"exit !\n");
}