[状态压缩DP] PKU 3311 Hie with the Pie

和COJ送货到家一样,不过这里不要求每个点只经过一次,因此可以先用floyd预处理出任意两点间的最短距离,然后状态压缩DP。

# include <cstdio>
# include <cstring>

# define INF 0x3C3C3C3C
# define N 10 + 2

int n;
int w[N][N];
int f[1<<N][N];

int Min(int x, int y)
{
    return x<y ? x:y;
}

int dp(int s, int i)
{
    int &ans = f[s][i];
    if (ans != -1) return ans;
    int ns = s&(~(1<<i));
    if (ns == 1) return ans = w[0][i];
    ans = INF;
    for (int j = 1; j < n; ++j) if (((s>>j)&0x1) && j!=i)
    {
        ans = Min(ans, dp(ns, j)+w[j][i]);
    }
    return ans;
}

void solve(void)
{
    int ans = INF;
    if (n==1) {puts("0");return ;}
    for (int i = 0; i < (1<<n); ++i)
        memset(f[i], -1, sizeof(int)*n);
       f[1][0] = 0;
    for (int i = 1; i < n; ++i)
    {
        ans = Min(ans, dp((1<<n)-1, i)+w[i][0]);
    }
    printf("%d\n", ans);
}

void read_graph(void)
{
    for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
        scanf("%d\n", &w[i][j]);
}

void rebuild_graph(void)
{
    for (int k = 0; k < n; ++k)
    for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
        w[i][j] = Min(w[i][j], w[i][k]+w[k][j]);        
}

int main()
{    
    while (scanf("%d", &n), n)
    {
        ++n;
        read_graph();
        rebuild_graph();
        solve();
       }
           
    return 0;
}
原文地址:https://www.cnblogs.com/JMDWQ/p/2624337.html