[状态压缩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; }