曼哈顿距离比曼哈顿距离+线性冲突更好

时间:2019-12-05 23:26:32

标签: c++

我尝试用曼哈顿距离和曼哈顿距离+线性冲突启发式算法来实现A *算法。 但是我的曼哈顿距离效果更好,我不明白为什么! 我的算法中的曼哈顿距离+线性冲突扩展了更多的节点,我发现它的回答甚至不是最优的。

#include <iostream>
#include <time.h>
#include <fstream>
#include <set>
#include <vector>
#include <queue>
#include <map>
#include "node.h"




using namespace std;

const int n = 4;
const int hash_base = 23;
const long long hash_mod = 9827870924701019;
set<long long> explored;
set<pair<int , node*> > frontier;
map<string,int> database[3];

void check(int* state){
    for(int j = 0 ; j < n ; j++){
    for(int i = 0 ; i < n ; i++)
        cerr << state[j * n + i] << " ";
        cerr << endl;
    }
    cerr << endl;
}

bool goal_test(int* state){
    if(state[n * n - 1] != 0) return 0;
    for(int i = 0 ; i < (n * n - 1) ; i++){
        if(state[i] != i + 1)
            return 0;
    }
    return 1;
}

vector<node> solution(node* v){
    vector<node> ans;
    while((v->parent)->hash != v->hash){
        ans.push_back(*v);
        v = v->parent;

    }
    return ans;
}
//first heuristic
int manhattanDistance(int* state){
    int md = 0;
    for(int i = 0 ; i < (n * n) ; i++){
        if(state[i] == 0) continue;
        //what is the goal row and column of this tile
        int gr = (state[i] - 1) / n , gc = (state[i] - 1) % n;
        //what is the row and column of this tile
        int r = i / n  , c = i % n;
        md += (max(gr - r , r - gr) + max(gc - c , c - gc));
    }
    return md;

}

//second heuristic
int linearConflict(int* state){
    int lc = 0;
    for(int i = 0 ; i < n ; i++){
        for(int j = 0 ; j < n ; j++){
            //jth tile in ith row = (i * n + j)th in state
            int la = i * n + j;
            if(state[la] == 0 || (state[la] / n) != i)
                continue;
            for(int k = j + 1 ; k < n ; k++){
                //kth tile in ith row = (i * n + k)th in state
                int lb = i * n + k;
                if(state[lb] == 0 || (state[lb] / n) != i)
                    continue;
                if(state[la] > state[lb])
                        lc++;
            }
        }
    }

    for(int i = 0 ; i < n ; i++){
        for(int j = 0 ; j < n ; j++){
            //j the tile of i th column
            int la = j * 4 + i;
            if(state[la] == 0 || (state[la] % n) != i)
                continue;
            for(int k = j + 1 ; k < n ; k++){
                int lb = k * 4 + i;
                if(state[lb] == 0 || (state[lb] % n) != i)
                    continue;
                if(state[la] > state[lb])
                    lc++;
            }
        }
    }

    return lc * 2;
}

long long make_hash(int* v){
    long long power = 1LL;
    long long hash = 0 * 1LL;
    for(int i = 0 ; i < (n * n) ; i++){
        hash += (power * v[i] * 1LL) % hash_mod;
        hash %= hash_mod;
        power = (hash_base * power * 1LL) % hash_mod;
    }
    return hash;
}


vector<node> successor(node* parent){
    vector<node> child;
    int parent_empty = parent->empty_cell;
    //the row and column of empty cell
    int r = parent_empty / n ,  c = parent_empty % n;

    //empty cell go down
    if(r + 1 < n){
        struct node down;

        for(int i = 0 ; i < (n*n) ; i++)
            down.state[i] = parent->state[i];

        down.state[parent_empty] = parent->state[parent_empty + n];
        down.state[parent_empty + n] = 0;

        down.hash = make_hash(down.state);
        down.empty_cell = parent_empty + n;
        down.cost = parent->cost + 1;
        down.parent = parent;
        //first heuristic -> manhattan Distance
        // down.heuristic = manhattanDistance(down.state);
        //second heuristic -> manhattan distance + linear conflict
        down.heuristic = linearConflict(down.state) + manhattanDistance(down.state);
        //third heuristic -> disjoint pattern database
        // down.heuristic = DisjointPatternDB(down.state);

        child.push_back(down);
    }

    //empty cell go up
    if(r - 1 >= 0){
        struct node up;

        for(int i = 0 ; i < n * n ; i++)        
            up.state[i] = parent->state[i];
        up.state[parent_empty] = parent->state[parent_empty - n];
        up.state[parent_empty - n] = 0;

        up.empty_cell = parent_empty - n;
        up.hash = make_hash(up.state);
        up.cost = parent->cost + 1;
        up.parent = parent;

        //first heuristic -> manhattan Distance
         // up.heuristic = manhattanDistance(up.state);
        //second heuristic -> manhattan distance + linear conflict
        up.heuristic = linearConflict(up.state) + manhattanDistance(up.state);
        //third heuristic -> disjoint pattern database
        // up.heuristic = DisjointPatternDB(up.state);

        child.push_back(up);
    }

    //empty cell going right
    if(c + 1 < n){
        struct node right;
        for(int i = 0 ; i < (n * n) ; i++)
            right.state[i] = parent->state[i];
        right.state[parent_empty] = parent->state[parent_empty + 1];
        right.state[parent_empty + 1] = 0;

        right.empty_cell = parent_empty + 1;
        right.hash = make_hash(right.state);
        right.cost = parent->cost + 1;
        right.parent = parent;

        //first heuristic -> manhattan Distance
         // right.heuristic = manhattanDistance(right.state);
        //second heuristic -> manhattan distance + linear conflict
        right.heuristic = linearConflict(right.state) + manhattanDistance(right.state);
        //third heuristic -> disjoint pattern database
        // right.heuristic = DisjointPatternDB(right.state);


        child.push_back(right);
    }
    //empty cell going left
    if(c - 1 >= 0){
        struct node left;

        for (int i = 0; i < (n * n) ; i++)
            left.state[i] = parent->state[i];

        left.state[parent_empty] = parent->state[parent_empty - 1];
        left.state[parent_empty - 1] = 0;

        left.empty_cell = parent_empty - 1;
        left.hash = make_hash(left.state);
        left.cost = parent->cost + 1;
        left.parent = parent;
        //first heuristic -> manhattan Distance
         // left.heuristic = manhattanDistance(left.state);
        //second heuristic -> manhattan distance + linear conflict
        left.heuristic = linearConflict(left.state) + manhattanDistance(left.state);
        //third heuristic -> disjoint pattern database
        // left.heuristic = DisjointPatternDB(left.state);

        child.push_back(left);
    }

    return child;
} 
node* nodeCopy(node child){
    node* tmp = new node;
    for(int i = 0 ; i < n * n; i++)
        tmp->state[i] = child.state[i];
    tmp->hash =  child.hash;
    tmp->empty_cell = child.empty_cell;
    tmp->cost = child.cost;
    tmp->parent =  child.parent;
    tmp->heuristic = child.heuristic;
    return tmp;
}


vector<node> Astar(node* initNode){
    if(goal_test(initNode->state)) return solution(initNode);
    frontier.insert(make_pair(initNode->cost + initNode-> heuristic ,initNode));
    explored.insert(initNode->hash);
    while(!frontier.empty()){
        node* v = (*frontier.begin()).second;
        if(goal_test(v->state)) return solution(v);
        frontier.erase(frontier.begin());
        vector<node> childs = successor(v);
        for(node child: childs){
            if(explored.find(child.hash) == explored.end()){
                node* tmp = nodeCopy(child);
                frontier.insert(make_pair((child.cost + child.heuristic) , tmp));
                explored.insert(child.hash);
            }
        }
    }
    return solution(initNode);
}





int main(){
    clock_t tStart = clock();
    printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
    struct node init;// {{1 , 2 , 3 , 4 , 5, 6, 7, 8, 0} , 1 , 9 , 0 , &init , 0};
    for(int i = 0 ; i < (n * n) ; i++){
        cin >> init.state[i];
        if(init.state[i] == 0)
            init.empty_cell = i;
    }
    init.hash = make_hash(init.state);
    init.cost = 0;
    init.parent = &init;
    init.heuristic = manhattanDistance(init.state) ;//+ linearConflict(init.state);




    vector <node> ans = Astar(&init);
    //cout << 1 << "   ";
    for(int j = 0 ; j < n * n ; j++){
            if(j == n * n - 1) cout << init.state[j];
            else cout << init.state[j] << ",";
    }
    cout << endl;
    for(int i = (ans.size() - 1) ; i >= 0  ; i--){
        //cout << (ans.size() - i + 1) << "   ";
        cerr << linearConflict(ans[i].state) << endl;
        for(int j = 0 ; j < n * n ; j++){
            if(j == n * n - 1) cout << ans[i].state[j];
            else cout << ans[i].state[j] << ",";
        }
        cout << endl;
    }
    cout << "path size : " << ans.size() << endl;
    cout << "number of node expanded : " << explored.size() << endl; 
    printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);


}
#include <vector>

using namespace std;



struct node{
    int state[16];
    long long hash;
    int empty_cell;
    long cost;
    node* parent;
    int heuristic;

};

1 个答案:

答案 0 :(得分:1)

如果答案不是最优,则是因为您的试探法不被接受。 这意味着有时高估了到达图中一个节点的成本。

线性冲突启发式方法应始终与曼哈顿(Manhattan)之类的距离估计启发式方法结合使用,它不像在每一行/每列中给出线性冲突数两倍的简单。

请参见Linear Conflict violating admissibility and driving me insane

https://cse.sc.edu/~mgv/csce580sp15/gradPres/HanssonMayerYung1992.pdf