?? 2288狀態(tài)壓縮dp(tsp問題).cpp
字號:
#include <iostream>
#define I64 __int64
using namespace std;
//狀態(tài)為f[i][j][k],表示經(jīng)過二進制數(shù)i所指的哈密頓路(第bi位為1表示經(jīng)過該點,為0表示不經(jīng)過該點),
//倒數(shù)第二個點為j,最后一個點為k。.value表示最大權(quán)值,.num表示能走出最大權(quán)值的路徑數(shù)。若圖中k到p有邊,f[i][j][k]則轉(zhuǎn)移到f[i'][k][p]。i' == i | (1 << p)。
struct Node
{
I64 val, num;
};
int n, m;
I64 c[13];
int g[13][13];
Node f[1<<13][13][13];
void dp(I64 &ans1, I64 &ans2)
{
if(n == 1){
ans1 = c[0];
ans2 = 2;
return ;
}
int i, j, k, p;
I64 t;
memset(f, 0, sizeof(f));
for(i = 0; i < n; i++) //每兩個有邊相連的結(jié)點
for(j = 0; j < n; j++) if(g[i][j]){
f[(1<<i) | (1<<j)][i][j].val = c[i] + c[j] + c[i]*c[j];
f[(1<<i) | (1<<j)][i][j].num = 1;
}
for(i = 0; i < (1<<n); i++){
for(j = 0; j < n; j++) if((i>>j)&1) {
for(k = 0; k < n; k++) if(((i>>k)&1) && f[i][j][k].val != 0){ //j,k結(jié)點有邊相連
for(p = 0; p < n; p++) if(((i>>p)&1) == 0 && g[k][p]){ //加入p結(jié)點
t = c[p] + c[p]*c[k];
if(g[j][p]) t += c[j]*c[k]*c[p]; //如果p,j有邊相連
//更新
if(f[i][j][k].val + t > f[i|(1<<p)][k][p].val){
f[i|(1<<p)][k][p].val = f[i][j][k].val + t;
f[i|(1<<p)][k][p].num = f[i][j][k].num;
}
else if(f[i][j][k].val + t == f[i|(1<<p)][k][p].val) //注意... 相等是方法數(shù)增加
f[i|(1<<p)][k][p].num += f[i][j][k].num;
}
}
}
}
ans1 = 0;
ans2 = 0;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
if(f[(1<<n) - 1][i][j].val > ans1){
ans1 = f[(1<<n) - 1][i][j].val;
ans2 = f[(1<<n) - 1][i][j].num;
}
else if(f[(1<<n) - 1][i][j].val == ans1)
ans2 += f[(1<<n) - 1][i][j].num;
}
}
return ;
}
int main()
{
//freopen("data.txt", "r", stdin);
int ca, i, s, t;
I64 ans1, ans2;
scanf("%d", &ca);
while(ca--){
scanf("%d%d", &n, &m);
for(i = 0; i < n; i++)
scanf("%I64d", &c[i]);
memset(g, 0, sizeof(g));
for(i = 0; i < m; i++){
scanf("%d%d", &s, &t);
s--;
t--;
g[s][t] = g[t][s] = 1;
}
dp(ans1, ans2);
printf("%I64d %I64d\n", ans1, ans2/2);
}
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -