• P2915 [USACO08NOV]Mixed Up Cows G 状压DP


    约翰家有N头奶牛,第i头奶牛的编号是Si,每头奶牛的编号都是唯一的。这些奶牛最近 在闹脾气,为表达不满的情绪,她们在挤奶的时候一定要排成混乱的队伍。在一只混乱的队 伍中,相邻奶牛的编号之差均超过K。比如当K = 1时,1, 3, 5, 2, 6, 4就是一支混乱的队伍, 而1, 3, 6, 5, 2, 4不是,因为6和5只差1。请数一数,有多少种队形是混乱的呢?
    (4<=N<=16,1<=si<=25000)

    数据范围这么小很明显就算是状压DP(一般不大于20),
    定义f[ i ] [ j ]表示状态为i时以j为末尾时的方案数(i二进制下第k位为1表示第k只牛在队列内,反之不在)。
    首先将牛的编号离散化 排好序方便找,那么当状态s不包含第i只牛时,第j只牛与第i只牛编号之差大于k时,s再加上i的状态下以第i只牛为末尾的方案就等于状态s下以j为末尾的方案的和(所有满足的j)
    所以状态转移方程:f [ s+1<<(i-1) ][ i ]+= f [ s ][ j ];

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=17;
    int n,m,s[N];
    ll f[1<<N][N];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",s+i);
    	sort(s+1,s+n+1);
    	for(int i=1;i<=n;i++) f[1<<(i-1)][i]=1;//初始化只有1个情况
    	for(int j=1;j<(1<<(n));j++)//暴力枚举所有状态,所以状压dp也是个暴力算法
    	{
    		for(int k=1;k<=n;k++)//枚举末尾的牛
    		{
    			if(j&(1<<(k-1))) continue;
    			int l=lower_bound(s+1,s+n+1,s[k]-m)-s;//第一个大于等于s[k]-m的位置,l前的牛都可以与k相邻,是s[k]不是k!!!
    			int r=upper_bound(s+1,s+n+1,s[k]+m)-s;//第一个大于s[k]+m的牛,从r到n牛也都可以
    			for(int o=1;o<l;o++)//不用判断j是否包含o,如果不包含f[j][o]一定等于0
    					f[j+(1<<(k-1))][k]+=f[j][o];
    			for(int o=r;o<=n;o++)
    					f[j+(1<<(k-1))][k]+=f[j][o];
    		}
    	}
    	ll ans=0;
    	for(int i=1;i<=n;i++)//将所有满状态下的方案相加
    		ans+=f[(1<<n)-1][i];
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    ajax专题
    luogu P1346 电车 最短路
    luogu P1462 通往奥格瑞玛的道路 最短路
    luogu P1328 生活大爆炸版石头剪刀布
    luogu P1315 联合权值 枚举
    luogu P1156 垃圾陷阱 背包问题
    luogu P1217 回文质数 枚举
    luogu P3650 滑雪课程设计 枚举
    luogu1209 修理牛棚 贪心
    luogu P1223 排队接水 贪心
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871761.html
Copyright © 2020-2023  润新知