汉密尔顿图+状压dp
用二进制数表示路径,压缩状态 dp[stat][last][last_one] 表示当前状态的权值 ways[stat][last][last_one] 表示当前状态的个数这里要注意的是如果 dp更新,ways要丢掉之前记录的个数,重新计数,否则累加。
代码有4重for循环,记得剪枝
dp用int 代替long long能快很多
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int Maxn = 13;
const int INF = 0x3f3f3f3f;
const long long LINF = 1e18;
bool G[Maxn+5][Maxn+5];
ll ways[(1<<Maxn)+5][Maxn+5][Maxn+5];
int dp[(1<<Maxn)+5][Maxn+5][Maxn+5], cost[Maxn+5];
void solve(int n) {
int maxn = -1;
for(int i = 3; i < (1<<n)-1; ++i) {
for(int j = 1; j <= n; ++j) {
if(!((i>>(j-1))&1)) continue;
for(int k = 1; k <= n; ++k) {
if(!((i>>(k-1))&1) || !G[j][k]) continue;
for(int v = 1; v <= n; ++v) {
if(!G[j][v] || dp[i][j][k] == -1) continue;
if((i>>(v-1))&1) continue;
int stat = (i|(1<<(v-1)));
if(G[v][j] && G[j][k] && G[v][k]) {
if(dp[stat][v][j] < dp[i][j][k]+cost[v]*cost[j]*(1+cost[k])) {
ways[stat][v][j] = ways[i][j][k];
} else if (dp[stat][v][j] == dp[i][j][k]+cost[v]*cost[j]*(1+cost[k])) {
ways[stat][v][j] += ways[i][j][k];
}
dp[stat][v][j] = max(dp[stat][v][j], dp[i][j][k]+cost[v]*cost[j]*(1+cost[k]));
} else {
if(dp[stat][v][j] < dp[i][j][k]+cost[v]*cost[j]) {
ways[stat][v][j] = ways[i][j][k];
} else if(dp[stat][v][j] == dp[i][j][k]+cost[v]*cost[j]) {
ways[stat][v][j] += ways[i][j][k];
}
dp[stat][v][j] = max(dp[stat][v][j], dp[i][j][k]+cost[v]*cost[j]);
}
}
}
}
}
ll sum = 0, cnt = 0;
for(int i = 1; i <= n; ++i) sum += cost[i];
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
if(maxn < dp[(1<<n)-1][i][j]) {
maxn = dp[(1<<n)-1][i][j];
cnt = ways[(1<<n)-1][i][j];
} else if(maxn == dp[(1<<n)-1][i][j]) {
cnt += ways[(1<<n)-1][i][j];
}
}
}
if(maxn == -1) printf("0 0\n");
else printf("%lld %lld\n", maxn+sum, cnt/2);
}
int main(void)
{
int T;
scanf("%d", &T);
while(T--) {
int n, m, u, v;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &cost[i]);
if(n == 1) printf("%d 1\n", cost[1]);
else {
memset(G, false, sizeof(G));
memset(dp, -1, sizeof(dp));
memset(ways, 0, sizeof(ways));
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &u, &v);
G[u][v] = G[v][u] = true;
dp[(1<<(u-1))|(1<<(v-1))][u][v] = dp[(1<<(u-1))|(1<<(v-1))][v][u] = cost[u]*cost[v];
ways[(1<<(u-1))|(1<<(v-1))][u][v] = ways[(1<<(u-1))|(1<<(v-1))][v][u] = 1;
}
solve(n);
}
}
return 0;
}
浙公网安备 33010602011771号