ABC079 D-Wallの精進

順列を全列挙して全探索

問題概要

数字C_{i,j}にiからjに変更するのに必要なコストが与えられるので、
数字A_{i,j}を全て1にするのに必要な魔力の最小量を求める

問題リンクは下記
https://beta.atcoder.jp/contests/abc079/tasks/abc079_d

解法

next_permutationを使って前処理で10!通りを全探索して通るのかと思いましたが10!×10くらいで最小コストは求められ、その後はO(1)でアクセスできるので
だいたい10^7くらいで求まりそうな見込みが立つので実装してみると通るという。(46msくらい)

想定解はワーシャルフロイドのようですが、ワーシャルフロイドが分かっていないのでワーシャルフロイドを今後は精進したいと思います。

#include<iostream>
#include<vector>
#include<algorithm>
#include<cctype>
#include<utility>
#include<string>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<queue>

#define REP(i, n) for(int i = 0;i < n;i++)
#define REPR(i, n) for(int i = n;i >= 0;i--)
#define FOR(i, m, n) for(int i = m;i < n;i++)
#define FORR(i, m, n) for(int i = m;i >= n;i--)
#define SORT(v, n) sort(v, v+n);
#define VSORT(v) sort(v.begin(), v.end());
#define llong long long
#define pb(a) push_back(a)
#define INF 1000000007
using namespace std;
typedef pair<int, int> P;
typedef pair<llong, llong> LP;
typedef pair<int, P> PP;
typedef pair<llong, LP> LPP;
typedef long long int ll;
ll dx[4] = {1,0,0,-1};
ll dy[4] = {0,1,-1,0};

#define ARRAY_MAX 205
int mp[ARRAY_MAX][ARRAY_MAX];
int magic[ARRAY_MAX][ARRAY_MAX];
int h,w;

int main(){

    cin >> h >> w;
    REP(i,10){
        REP(j,10){
            cin >> mp[i][j];
        }
    }
    REP(i,h){
        REP(j,w){
            cin >> magic[i][j];
        }
    }

    vector<int> mini(10,INF);//iから1にするのに必要な最小コスト
    vector<int> num(10);//最小値
    mini[1] = 0;
    REP(i,10){
        num[i] = i;
    }

    do{
        int power = 0;
        if(num[0] == 1){
            //1はとばす
            continue;
        }
        REP(i,9){
            power += mp[num[i]][num[i+1]];//順列に従って変更していく
            if(num[i+1] == 1){
                //1にたどり着いたら終了
                break;
            }
        }
        mini[num[0]] = min(mini[num[0]],power);//最小値の更新

    }while(next_permutation(num.begin(),num.end()));

    int ans = 0;//全て1に変更するのに必要な魔力
    REP(i,h){
        REP(j,w){
            if(magic[i][j] == -1){
                continue;
            }
            ans += mini[magic[i][j]];
        }
    }
    cout << ans << endl;

    return 0;
}