C言語で書いてみました

過去の情報処理技術者試験の出題をもとにして、Cのソースを起こしてみました。

■ 巡回セールスマン問題(平成18年秋午後2問1)

/*
 *  ソフトウェア開発技術者
 *  平成18年度秋午後2問1
 *
 *  巡回セールスマン問題
 *
 */

#include <stdio.h>

#define SETSUMON    1 /* 0:設問3, 1:設問2(2) */ 

#define mod(k,n)    ((k)%(n))
#define floor(k,n)  ((k)/(n))
#define true        1
#define false       0

#define X           32767 /* 十分大きな値 */


#if SETSUMON==0
    #define n   4 /* ノードの数 */
    int D[n][n] = {
        {  X,  55, 50,  70 },
        { 55,   X, 60, 120 },
        { 50,  60,  X,  65 },
        { 70, 120, 65,   X },
    };
#else
    #define n   5 /* ノードの数 */
    int D[n][n] = {
        { X, 5, 4, 8, 7 },
        { 5, X, 7, 5, 7 },
        { 4, 7, X, 8, 2 },
        { 8, 5, 8, X, 4 },
        { 7, 7, 2, 4, X },  
    };
#endif

int tour[n], length;

/*  Nearest Neighbor 法 */
void Nearest_Neighbor(void)
{
    int visited[n], min, min_j, current;
    int i, j;
    for (i = 0; i <= n - 1; i++)
        visited[i] = false; /* 初期化 */
    current = 0;
    for (i = 0; i <= n - 1; i++) {
        tour[i] = current;
        visited[current] = true;
        min = X;
        for (j = 0; j <= n - 1; j++) {
            if (visited[j] == false && D[current][j] < min) {
                min = D[current][j];
                min_j = j;
            }
        }
        current = min_j;
    }
    length = 0;
    for (i = 0; i <= n - 1; i++) /* 巡回路の重みの算出 */
        length = length + D[tour[i]][tour[mod(i+1,n)]];
}

/* 2-opt による改良 */
void step_two(int start)
{
    int i, j, k, diff, temp;
    for (i = start; i <= start + n - 1; i++) {
        for (k = i + 2; k <= i + n - 2; k++) {
            diff = (D[tour[mod(i,n)]][tour[mod(i+1,n)]]
                    + D[tour[mod(k,n)]][tour[mod(k+1,n)]])
                 - (D[tour[mod(i,n)]][tour[mod(k,n)]]
                    + D[tour[mod(i+1,n)]][tour[mod(k+1,n)]]);
            if (diff > 0) { /* より重みの小さい巡回路が見出された */
                length = length - diff;
                for (j = 0; j <= floor(k-i,2) - 1; j++) {
                    /* 巡回路の一部分を反転する */
                    temp = tour[mod(i+1+j,n)];
                    tour[mod(i+1+j,n)] = tour[mod(k-j,n)];
                    tour[mod(k-j,n)] = temp;
                }
                return;
            }
        }
    }
}

/* 表示 */
void print(void)
{
    int i;
    printf("巡回路の重み:%d [", length);
    for (i = 0; i < n; i++)
        printf("%d->", tour[i]);
    printf("%d]\n", tour[0]);
}

/* テスト */
int main()
{
    Nearest_Neighbor();
    print();
    step_two(1);
    print();

    return 0;
}