dijkstra | spin on the RITZ

dijkstra

ダイクストラはかくかたりき



#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

#define BUTTON_START    0
#define BUTTON_RESET    1
#define BUTTON_MINEDGE  2

#define WINDOW_HEIGHT 450
#define WINDOW_WIDTH  450

#define NODE_NUM 30
#define NODE_R   7

POINT   node[NODE_NUM];
int  dmat[NODE_NUM][NODE_NUM]; 
int  is_edge[NODE_NUM][NODE_NUM]; 
int  min_edge[NODE_NUM][NODE_NUM];   
int  min_dist[NODE_NUM];       
int  start = 0;               

HBRUSH  first_color; 
HBRUSH  node_color;    
HPEN    edge_color;  
HPEN    me_color;     

void dijkstra(void)
{
    int done[NODE_NUM];
    int min, min_idx;
    int i, j, k, t;

    for (i = 0;i < NODE_NUM;i++)
        min_dist[i] = INT_MAX;
    min_dist[start] = 0;
    memset(done, 0, sizeof(done));
    memset(min_edge, 0, sizeof(min_edge));
    for (i = 1;i < NODE_NUM;i++) {
        min = INT_MAX;
        for (j = 0;j < NODE_NUM;j++) {
            if (!done[j] && min_dist[j] < min) {
                min = min_dist[j];
                min_idx = j;
            }
        }
        done[min_idx] = 1;
        for (k = 0;k < NODE_NUM;k++) {
            if (!done[k] && dmat[min_idx][k] != -1) {
                if (min_dist[k] > min_dist[min_idx]+dmat[min_idx][k]) {
                    for (t = 0;t < NODE_NUM;t++)
                        min_edge[k][t] = 0;
                    min_edge[k][min_idx] = 1;
                }
                min_dist[k] = min(min_dist[k], min_dist[min_idx]+dmat[min_idx][k]);

            }
        }
    }
}

int distance(int sx, int sy, int ex, int ey)
{
    int x2 = (sx-ex)*(sx-ex);
    int y2 = (sy-ey)*(sy-ey);

    return (int)sqrt(x2+y2);
}

void init_node(void)
{
    int i;

    for (i = 0;i < NODE_NUM;i++) {
        do {
            node[i].x = rand()%(WINDOW_HEIGHT-50)+20;
            node[i].y = rand()%(WINDOW_HEIGHT-50)+20;
        } while (node[i].x >= 360 && node[i].y <=70);
    }
}

void init_edge(void)
{
    int i, k, dist, cnt, rnd;
    int n = 10;

    memset(min_edge, 0, sizeof(min_edge));
    memset(is_edge, 0, sizeof(is_edge));

    for (i = 0;i < NODE_NUM;i++) {
        cnt = 0;
        for (k = 0;k < NODE_NUM;k++) {
            dist = distance(node[i].x, node[i].y, node[k].x, node[k].y);
            if (rand()%n==0 && dist < 250) {
                is_edge[i][k] = is_edge[k][i] = 1;
                cnt++;
            }
        }
        if (cnt == 0) {
            while ((rnd=rand()%NODE_NUM) == i)
                /* rnd != i になるまで回す */;

            is_edge[i][rnd] = is_edge[rnd][i] = 1;
        }
    }

}

void init_dmat(void)
{
    int i, k;

    memset(dmat, -1, sizeof(dmat));
    for (i = 0;i < NODE_NUM;i++)
        for (k = i+1;k < NODE_NUM;k++)
            if (is_edge[i][k] == 1)
                dmat[i][k] = dmat[k][i] = distance(node[i].x, node[i].y,node[k].x, node[k].y);

    for (i = 0;i < NODE_NUM;i++)
        dmat[i][i] = 0;
}

void init_pb(void)
{
    me_color    = CreatePen(PS_SOLID, 1, RGB(0xff, 0, 0));
    edge_color  = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
    first_color = CreateSolidBrush(RGB(0xff, 0, 0));
    node_color  = CreateSolidBrush(RGB(0xff, 0xff, 0xff));
}

void delete_pb(void)
{
    DeleteObject(me_color);
    DeleteObject(edge_color);
    DeleteObject(first_color);
    DeleteObject(node_color);
}

void DrawLine(HDC hdc, int xs, int ys, int xe, int ye)
{
    MoveToEx(hdc, xs, ys, NULL);
    LineTo(hdc, xe, ye);
    MoveToEx(hdc, 0, 0, NULL);
}

void DrawCircle(HDC hdc, int x, int y)
{
    Ellipse(hdc, x-NODE_R, y-NODE_R, x+NODE_R, y+NODE_R);
}

void Draw_Node(HDC hdc)
{
    int i;

    SelectObject(hdc ,edge_color);
    SelectObject(hdc ,first_color);
    DrawCircle(hdc, node[start].x, node[start].y);

    SelectObject(hdc , node_color);
    for (i = 0;i < NODE_NUM;i++)
        if (i != start)
            DrawCircle(hdc, node[i].x, node[i].y);

}

void Draw_Edge(HDC hdc)
{
    int i, k;

    SelectObject(hdc, edge_color);
    for (i = 0;i < NODE_NUM;i++) {
        for (k = i+1;k < NODE_NUM;k++) {
            if (is_edge[i][k]) {
                DrawLine(hdc, node[i].x, node[i].y, node[k].x, node[k].y);
            }
        }
    }

}

void Draw_MinEdge(HDC hdc)
{
    int i, k;

    SelectObject(hdc, me_color);
    for (i = 0;i < NODE_NUM;i++) {
        for (k = 0;k < NODE_NUM;k++) {
            if (min_edge[i][k])
                DrawLine(hdc, node[i].x, node[i].y, node[k].x, node[k].y);  
        }
    }
}

int SearchNode(POINT pt)
{
    int x = pt.x;
    int y = pt.y;
    int i;

    for (i = 0;i < NODE_NUM;i++) {
        if (i == start)
            continue;
        if (node[i].x-NODE_R <= x && x <= node[i].x+NODE_R &&
            node[i].y-NODE_R <= y && y <= node[i].y+NODE_R) {
                start = i;
                return 1;
        }
    }

    return 0;
}

void output_data(void)
{
    FILE *fp;
    int i, k;

    fp = fopen("result.txt", "w");

    fprintf(fp, "ノード\n");
    for (i = 0;i < NODE_NUM;i++)
        fprintf(fp, "%2d: (x,y) = (%3ld, %3ld)\n", i, node[i].x, node[i].y);
    fprintf(fp, "辺があるか\n");
    for (i = 0;i < NODE_NUM;i++) {
        for (k = 0;k < NODE_NUM;k++)
            fprintf(fp, "%d ", is_edge[i][k]);
        fprintf(fp, "\n");
    }
    fprintf(fp, "距離行列\n");
    for (i = 0;i < NODE_NUM;i++) {
        for (k = 0;k < NODE_NUM;k++)
            fprintf(fp, "%3d ", dmat[i][k]);
        fprintf(fp, "\n");
    }
    fprintf(fp, "最短距離に関わる辺\n");
    for (i = 0;i < NODE_NUM;i++) {
        for (k = 0;k < NODE_NUM;k++)
            fprintf(fp,"%d ", min_edge[i][k]);
        fprintf(fp, "\n");
    }
    fprintf(fp, "最短距離\n");
    for (i = 0;i < NODE_NUM;i++)
        fprintf(fp, "%d %d\n", i,min_dist[i]);
}

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp)
{
    HDC hdc;
    PAINTSTRUCT ps;
    POINT pt;
    static int visible_edge = 1;

    switch (msg) {
        case WM_CREATE:
            srand((unsigned int)time(NULL));
            init_node();
            init_edge();
            init_dmat();
            init_pb();
            return 0;
        case WM_DESTROY:
            delete_pb();
            PostQuitMessage(0);
            return 0;
        case WM_COMMAND:
            switch (LOWORD(wp)) {
                case BUTTON_START:
                    dijkstra();
                    InvalidateRect(hwnd,NULL,TRUE);
                    break;
                case BUTTON_RESET:
                    init_node();
                    init_edge();
                    init_dmat();
                    visible_edge = 1;
                    InvalidateRect(hwnd,NULL,TRUE);
                    break;
                case BUTTON_MINEDGE:
                    visible_edge = (visible_edge == 1) ? 0 : 1;
                    InvalidateRect(hwnd,NULL,TRUE);
                    break;
            }
        case WM_LBUTTONDOWN:
            pt.x = LOWORD(lp);
            pt.y = HIWORD(lp);
            if (SearchNode(pt))
                    InvalidateRect(hwnd,NULL,TRUE);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd , &ps);
            Draw_Node(hdc);
            if (visible_edge)
                Draw_Edge(hdc);
            Draw_MinEdge(hdc);

            EndPaint(hwnd , &ps);
            return 0;
    }
    return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS winc;

    winc.style    = CS_HREDRAW | CS_VREDRAW;
    winc.lpfnWndProc    = WndProc;
    winc.cbClsExtra     = 0;
    winc.cbWndExtra  = 0;
    winc.hInstance   = hInstance;
    winc.hIcon    = LoadIcon(NULL, IDI_APPLICATION);
    winc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    winc.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
    winc.lpszMenuName   = NULL;
    winc.lpszClassName  = TEXT("TEST");

    if (!RegisterClass(&winc))
        return -1;

    hwnd = CreateWindow(
        TEXT("TEST"), TEXT("Dijkstra"),
        (WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX) | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT,
        WINDOW_WIDTH+9, WINDOW_HEIGHT+35,
        NULL, NULL, hInstance, NULL
    );

    if (hwnd == NULL)
        return -1;

    CreateWindow(
        TEXT("BUTTON") , TEXT("Start") ,
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
        WINDOW_WIDTH-80 , 2 , 80 , 23 ,
        hwnd , (HMENU)BUTTON_START , hInstance , NULL
    );

    CreateWindow(
        TEXT("BUTTON") , TEXT("Reset") ,
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
        WINDOW_WIDTH-80 , 27 , 80 , 23 ,
        hwnd , (HMENU)BUTTON_RESET , hInstance , NULL
    );

    CreateWindow(
        TEXT("BUTTON") , TEXT("Min edge") ,
        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
        WINDOW_WIDTH-80 , 52 , 80 , 23 ,
        hwnd , (HMENU)BUTTON_MINEDGE , hInstance , NULL
    );

    while (GetMessage(&msg, NULL, 0, 0))
        DispatchMessage(&msg);

    return msg.wParam;
}