POJ2288 Islands and Bridges (状压dp)

本题就是经典的哈密顿回路,但是有一个附加条件,就是如果有三个相邻,那么可以附加值

这样我们就可以枚举4维,判断条件后再加上

本题有几个坑点

1.爆int

2.有可能不存在这样的路

3.题目定义的路是不重复的,所以要/2

4.本题应该先预处理两个的情况,再用他推大的情况,我们普通的是用小的来维护现在,而这道题用现在来维护以后

其实可以不用预处理,在循环内判断,但是预处理比较简单

5.我们设计的状态为f[i][j][k],当前集合为i,在j,由k跳过来

6.特判一个点的情况

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string> 
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=14;
const int inf=0x3f3f3f3f;
ll f[1<<N][N][N];
ll num[1<<N][N][N];
int n,m;
int g[N][N];
int w[N]; 
int main(){
    int i,j,k;
    int q;
    cin>>q;
    while(q--){
        memset(num,0,sizeof num);
        memset(g,0,sizeof g);
        cin>>n>>m;
    for(i=0;i<n;i++)
    cin>>w[i];
    for(i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u-1][v-1]=1;
        g[v-1][u-1]=1;
    }
    if(n==1){
        cout<<w[0]<<" 1"<<endl;
        continue;
    }
    memset(f,-1,sizeof f);
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            if(g[i][j]){
                f[1<<i|1<<j][i][j]=w[i]+w[j]+w[i]*w[j];
                num[1<<i|1<<j][i][j]=1;
            }
        }
    }
    int l;
    for(i=3;i<1<<n;i++){
        for(j=0;j<n;j++){
            if(!(i>>j&1))
            continue;
            for(k=0;k<n;k++){
                if(k==j||!(i>>k&1))
                continue;
                if(f[i][j][k]==-1) 
                continue;
                for(l=0;l<n;l++){
                    if(i>>l&1||!g[j][l])
                    continue;
                    int r=i|(1<<l);
                    ll tmp=f[i][j][k]+w[j]*w[l]+w[l];
                    if(g[k][l])
                    tmp+=w[k]*w[j]*w[l];
                    if(f[r][l][j]<tmp){
                        f[r][l][j]=tmp;
                        num[r][l][j]=num[i][j][k];
                    }            
                    else if(f[r][l][j]==tmp){
                        num[r][l][j]+=num[i][j][k];
                    }
                }                
            }
        } 
    }
    ll ans=0;
    ll res=0;
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            if(f[(1<<n)-1][i][j]>ans){
                ans=f[(1<<n)-1][i][j];
                res=num[(1<<n)-1][i][j];
            }
            else if(f[(1<<n)-1][i][j]==ans){
                res+=num[(1<<n)-1][i][j];
            }
        }
    }
    if(!ans)
    cout<<"0 0"<<endl;
    else
    cout<<ans<<" "<<res/2<<endl;
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/ctyakwf/p/12391705.html
今日推荐