CF11D A Simple Task

垃圾状压dp,应该根本没有紫题难度     

设当前状态为state,起点为state包含的元素中最小的一个,防止重复,以及当前所在地点u    

注意自环,就是两个点来回走的。在答案里修改也可以。我是直接在ans更新时判断state是否合法,是否包含至少3个元素      

然后一个答案会两种时针方式走,所以最终答案要处以2    

代码:      

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[20][600005]={0},ans=0;
int n,m;
int hed[5005],tal[5005],nxt[5005],cnt=0;
inline void addege(int x,int y){
    cnt++;
    tal[cnt]=y;
    nxt[cnt]=hed[x];
    hed[x]=cnt;
} 
bool ck(int state){
    int cnt=0;
    for(int i=1;i<=n;i++){
        if((state&(1<<(i-1)))==(1<<(i-1))){
            cnt++;
        }
    }
    if(cnt<=2) return 0;
    return 1;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addege(x,y);
        addege(y,x);
    }
    for(int i=1;i<=n;i++){
        f[i][1<<(i-1)]=1ll; 
    } 
    for(int state=1;state<(1<<n);state++){
        int st,u;
        for(int i=1;i<=n;i++){
            if((state&(1<<(i-1)))==(1<<(i-1))){
                st=i;
                break;
            }
        }
        for(int i=1;i<=n;i++){
            if((state&(1<<(i-1)))!=(1<<(i-1))) continue;
            u=i;
            for(int j=hed[u];j;j=nxt[j]){
                int v=tal[j];
                if(v<st) continue;
                if((state&(1<<(v-1)))==(1<<(v-1))){
                    if(v==st&&ck(state)) ans+=f[u][state]/*printf("st:%d,state:%d,f[u][state]:%d\n",st,state,f[u][state])*/;
                }
                else f[v][state|(1<<(v-1))]+=f[u][state];
            }
        }
    }
    cout<<ans/2<<endl;
    return 0;
} 

 

posted @ 2019-08-27 21:41  QYJ060604  阅读(148)  评论(0编辑  收藏  举报