这题说实话,完全没思路,看了题解才明白,题意:有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;
}