这题说实话,完全没思路,看了题解才明白,题意:有n个m个低点,每个地点都要花钱,每个人去每个地点都有一个兴趣值,如果两个人一起组队就会有福利,多个人就两两结合的福利加在一起。问怎么让这些值综合最大。
那么设计这样的状态:dp[i][s] 表示在第i个城市时状态为s的最大值,其实s状态里面包含的就是人的排列组合。
next[i][j] :状态i变成第j个的状态是什么 cnt[i] 状态i能变成几个状态 val[i] :城市i能得到总值。
#include<iostream> #include<algorithm> #include<stdlib.h> #include<string.h> #include<stdio.h> #include<math.h> #include<string> #include<vector> #include<queue> #include<list> using namespace std; #define ep 1e-9 #define oo 0x3f3f3f3f typedef __int64 lld; int dp[12][(1 << 10) + 1]; int nxt[1 << 11][1 << 11]; int cnt[1 << 11], val[11][1 << 11]; int cost[12], b[12][12], inte[12][12]; int n, m; void GetStatus() { for (int i = 0; i < (1 << 11); i++) for (int j = 0; j < (1 << 11);j++) if ((i&j) == j) nxt[i][cnt[i]++] = j; } int Dp() { int ans = -oo, Status = 1 << n; memset(val, 0, sizeof val); for (int i = 0; i < m; i++) for (int st = 0; st <= Status; st++) { for (int j = 0; j < n; j++) { if (!(st&(1 << j))) continue; for (int k = j - 1; k >= 0; k--) { if (!(st&(1 << k))) continue; val[i][st] += b[j][k]; } val[i][st] += (inte[j][i] - cost[i]); } } memset(dp, -0x3f, sizeof dp); for (int i = 0; i <= Status; i++) dp[0][i] = val[0][i]; for (int i = 1; i < m; i++) { for (int j = 0; j <= Status; j++) { for (int k = 0; k < cnt[j]; k++) dp[i][nxt[j][k]] = max(dp[i][nxt[j][k]], dp[i - 1][j] + val[i][nxt[j][k]]); } } for (int i = 0; i <= Status; i++) ans = max(ans, dp[m - 1][i]); return ans; } int main() { GetStatus(); while (scanf("%d %d", &n, &m) && (n || m)) { for (int i = 0; i < m; i++) scanf("%d", &cost[i]); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) scanf("%d", &inte[i][j]); for (int i = 0; i < n;i++) for (int j = 0; j < n; j++) scanf("%d", &b[i][j]); int ans = Dp(); if (ans <= 0) printf("STAY HOME\n"); else printf("%d\n", ans); } return 0; }