POJ 2288(状态压缩经典(巨坑)例题)

写了一天,还是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去除题意中的重复 
  
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值