写了一天,还是WA,后来看了大佬的题解,贴一下链接
https://blog.csdn.net/ouqingliang/article/details/70134970
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>//POJ不能用 #include<bits/stdc++.h>
using namespace std;
const int maxn=14;
typedef long long ll;
int v[maxn];//点权值
ll dp[1<<maxn][maxn][maxn];
ll num[1<<maxn][maxn][maxn];//注意方案数可能会爆int
bool p[maxn][maxn];//判断是否连通
int n,m;
long long ans,sum,rr;
int T;
inline void init(){//初始化
memset(v,0,sizeof v);
memset(dp,-1,sizeof dp);//用于判断阶段的可行性
memset(num,0,sizeof num);
memset(p,0,sizeof p);
ans=sum=0;
}
int main() {
cin>>T;
while(T--){
init();
cin>>n>>m;
for(int i=0;i<n;i++){
scanf("%d",&v[i]);
}
for(int i=1,f,t;i<=m;i++){
scanf("%d%d",&f,&t);
f--,t--;
p[f][t]=p[t][f]=1;//无向图
}
if(n==1){//注意图中只有一个点 权值与方法数
cout<<v[0]<<' '<<1<<endl;
continue;
}
for(int i=0;i<n;i++)//预处理边界值
for(int j=0;j<n;j++){
if(i!=j&&p[i][j]){
dp[(1<<i)|(1<<j)][i][j]=v[i]*v[j]+v[i]+v[j];
num[(1<<i)|(1<<j)][i][j]=1;//连接所有的边,并计算边权值
}
}
//三维的状态压缩
long long jd=1<<n;//状态压缩dp的边界
for(int k=0;k<jd;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(i!=j&&(p[i][j])&&(k&(1<<i))&&(k&(1<<j))){//ij直接存在路且当前状态经过ij
for(int a=0;a<n;a++){
if(i!=a&&j!=a&&p[j][a]&&(k&(1<<a))&&dp[k-(1<<i)][j][a]!=-1){//判断上一阶段是否可行
int cal=1ll*v[i]*v[j]+1ll*dp[k-(1<<i)][j][a]+ (p[i][a]?v[i]*v[j]*v[a]:0ll)+v[i];//计算权值
if(dp[k][i][j]<cal){
num[k][i][j]=num[k-(1<<i)][j][a];
dp[k][i][j]=cal;
}
else if(dp[k][i][j]==cal){
num[k][i][j]+=num[k-(1<<i)][j][a];
}
}
}
}
}
rr=0;
ans=-1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i!=j){
if(ans<dp[jd-1][i][j]){
rr=1ll*num[jd-1][i][j];
ans=dp[jd-1][i][j];
}
else if(ans==dp[jd-1][i][j]) rr+=1ll*num[jd-1][i][j];
//cout<<dp[jd-1][i][j]<<endl;
}
if(ans==-1) {//不连通
cout<<"0 0\n";
}
else cout<<ans<<' '<<rr/2<<endl;//rr/2去除题意中的重复
}
}