题目链接:http://poj.org/problem?id=2288
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 13; typedef long long int ll_int; ll_int dp[maxn][maxn][1<<maxn]; ll_int way[maxn][maxn][1<<maxn]; int G[maxn][maxn]; int V[maxn]; int main() { freopen("E:\acm\input.txt","r",stdin); int T; cin>>T; while(T--){ int n,m; cin>>n>>m; memset(G,0,sizeof(G)); memset(dp,0,sizeof(dp)); memset(way,0,sizeof(way)); for(int i=0;i<n;i++) cin>>V[i]; for(int i=0;i<m;i++){ int x,y; cin>>x>>y; G[x-1][y-1] = 1; G[y-1][x-1] = 1; } if(n == 1){ printf("%d 1 ",V[0]); continue; } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++){ if(G[i][j]){ dp[i][j][(1<<i)|(1<<j)] = V[i] + V[j] + V[i]*V[j]; dp[j][i][(1<<i)|(1<<j)] = V[i] + V[j] + V[i]*V[j]; //先处理相邻的两点的; way[i][j][(1<<i)|(1<<j)] = 1; way[j][i][(1<<i)|(1<<j)] = 1; } } int All = (1<<n) - 1; for(int S = 3;S <= All; S++){ //在每个状态下枚举状态内的点i,j,扩展出节点k.挺暴力的。 for(int i=0;i<n;i++){ if(!(1<<i & S)) continue; for(int j=0;j<n;j++){ if(!(1<<j & S) || i == j || !dp[i][j][S]) continue; for(int k=0;k<n;k++){ if((1<<k)&S || !G[j][k]) continue; int r = S + (1<<k); ll_int q = dp[i][j][S] + V[k] + V[j]*V[k]; if(G[i][k]){ q += V[i]*V[j]*V[k]; } if(q > dp[j][k][r]){ dp[j][k][r] = q; way[j][k][r] = way[i][j][S]; } else if(q == dp[j][k][r]){ way[j][k][r] += way[i][j][S]; } } } } } ll_int ans,answay; ans = 0; answay = 0; for(int i=0;i<n;i++) for(int j=0;j<n;j++){ if(i!=j){ if(dp[i][j][All] > ans){ ans = dp[i][j][All]; answay = way[i][j][All]; } else if(dp[i][j][All] == ans ){ answay += way[i][j][All]; } } } if(ans == 0) printf("0 0 "); else printf("%I64d %I64d ",ans,answay/2); } }