zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    WordPress让文本小工具支持简码
    修改WordPress后台登录地址,提高安全性
    WordPress用键盘左右方向键来查看上一篇和下一篇文章
    Git 补丁操作
    Git 标签操作
    Git 修正错误
    Git 删除操作
    Git 重命名操作
    Git 移动操作
    Git 藏匿操作
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871761.html
Copyright © 2011-2022 走看看