HDU4568 Hunter

题意\(n*m\)的矩形,每个格子有权值,并给出若干个在矩阵中的点的位置,要求从矩阵外任意位置进入矩阵到达所有给定的点并出去,求路径上最小权值和

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 210;
const int inf = 0x3f3f3f3f;
struct node
{
    int x, y;
    node(int _x = 0, int _y = 0) : x(_x), y(_y) {}
} s[15];
struct qnode
{
    int x, y;
    int c;
    qnode(int _x = 0, int _y = 0, int _c = 0) : x(_x), y(_y), c(_c) {}
    bool operator<(const qnode &r) const
    {
        return c > r.c;
    }
};
int a[maxn][maxn], n, m;
int dis[15][15];
int dist[maxn][maxn], vis[maxn][maxn];
int out[15];
int dp[1 << 15][15];
int dir[4][2] = {
    1, 0,
    0, 1,
    -1, 0,
    0, -1
};
bool limit(int x, int y)
{
    return x >= 0 && x < n && y >= 0 && y < m && a[x][y] != -1;
}
void dij(node st, int id)
{
    memset(dist, 0x3f, sizeof(dist));
    priority_queue<qnode> que;
    dist[st.x][st.y] = 0;
    que.push(qnode(st.x, st.y, 0));
    qnode tmp;
    while (!que.empty())
    {
        tmp = que.top();
        que.pop();
        node u = node(tmp.x, tmp.y);
        if (vis[u.x][u.y] == id)
            continue;
        vis[u.x][u.y] = id;
        for (int i = 0; i < 4; i++)
        {
            node now = node(u.x + dir[i][0], u.y + dir[i][1]);
            if (limit(now.x, now.y))
            {
                int cost = a[now.x][now.y];
                if (vis[now.x][now.y] != id && dist[now.x][now.y] > dist[u.x][u.y] + cost)
                {
                    dist[now.x][now.y] = dist[u.x][u.y] + cost;
                    que.push(qnode(now.x, now.y, dist[now.x][now.y]));
                }
            }
        }
    }
}
int main()
{
    int t, k;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                scanf("%d", &a[i][j]);
        scanf("%d", &k);
        for (int i = 0; i < k; i++)
            scanf("%d%d", &s[i].x, &s[i].y);
        memset(out, inf, sizeof(out));
        memset(vis, 0, sizeof(vis));
        memset(dp, inf, sizeof(dp));
        for (int i = 0; i < k; i++)
        {
            dij(s[i], i + 1);
            for (int j = 0; j < k; j++)
                dis[i][j] = dist[s[j].x][s[j].y]; //i到j的最短距离,不包括i点权值
            for (int j = 0; j < n; j++)
            {
                if (out[i] > dist[j][0])
                    out[i] = dist[j][0];
                if (out[i] > dist[j][m - 1])
                    out[i] = dist[j][m - 1];
            }
            for (int j = 0; j < m; j++)
            {
                if (out[i] > dist[0][j])
                    out[i] = dist[0][j];
                if (out[i] > dist[n - 1][j])
                    out[i] = dist[n - 1][j];
            }
            dp[1 << i][i] = out[i] + a[s[i].x][s[i].y];  //边界到该点的最短距离,加上该点权值
        }
        for (int i = 0; i < (1 << k); i++)
            for (int j = 0; j < k; j++)
                for (int _k = 0; _k < k; _k++)
                    if ((i & (1 << j)) == 0)
                        dp[i | (1 << j)][j] = min(dp[i | (1 << j)][j], dp[i][_k] + dis[_k][j]);
        int val = inf;
        for (int i = 0; i < k; i++)
            if (val > dp[(1 << k) - 1][i] + out[i])
                val = dp[(1 << k) - 1][i] + out[i];
        if (val == inf)
            puts("0");
        else
            printf("%d\n", val);
    }
    return 0;
}
posted @ 2020-03-01 21:19  Zeronera  阅读(91)  评论(0)    收藏  举报