看数据范围n<=10,所以不是搜索就是状压dp,又因为搜索会超时所以用dp

dp[i][k][j]表示现已经放到第i行,前面共有k个,这一行状态为j

so,dp[i][k][j]=dp[i-1][k-num[j]][t]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define low_bit(x) x&-x;
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
long long dp[11][1001][1001];//dp[i][j][k]表示前i行放k个且第i行的状态为j
long long n,k,s[1001],num[1001];
long long cont(long long x)
{
    long long c=0;
    while(x!=0) 
    {
        x-=low_bit(x);
        c++;
    }
    return c;
}
int main()
{
    n=read(),k=read();
    long long ans=0;
    for(long long i=0;i<(1<<n)-1;i++)
    {
        if((i&(i<<1)))continue;
            s[++ans]=i;
            num[ans]=cont(i);
    }
    dp[0][1][0]=1;
//    for(long long i=1;i<=ans;i++) cout<<s[i]<<" ";cout<<endl;
    for(long long i=1;i<=n;i++)
    {
        for(long long j=1;j<=ans;j++)
        {
            for(long long kk=0;kk<=k;kk++)
            {
                if(kk>=num[j])
                {
                    for(long long t=1;t<=ans;t++)
                    {
                        if(s[t]&s[j]) continue;
                        if(s[t]&(s[j]<<1)) continue;
                        if(s[t]&(s[j]>>1)) continue;
                        dp[i][j][kk]+=dp[i-1][t][kk-num[j]]; 
//                        cout<<dp[i][j][k]<<endl;
                    }
                }
            }
        }
    }
    long long sum=0;
    for(long long i=1;i<=ans;i++) sum+=dp[n][i][k];
    cout<<sum;
}
View Code

#loj 10171. 「一本通 5.4 例 2」牧场的安排

一道比较普通的状压dp,关键点就是输入时候怎么处理荒草

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mod 100000000
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
long long m,n;
//dp[i][j]表示第i行用第j个状态
//dp[i][j]+=dp[i-1][k]
long long dp[20][10001]; 
long long ans[20];//ans[i]表示第i行有ans[i]个状态
long long s[20][10001];//s[i][j]表示第i行第j个状态 
void init(long long h,long long t)
{
//    cout<<t<<endl;
    for(long long i=0;i<=(1<<n)-1;i++)
    {
        if((i&(i<<1))||(i&(i>>1))||(i&t)) continue;
        s[h][++ans[h]]=i;
    }
    return; 
}
int main()
{
    m=read(),n=read();
    for(long long i=1;i<=m;i++)
    {
        long long s=0;
        for(long long j=1;j<=n;j++) 
        {
            long long x=read();
            s=(s<<1)+1-x;
        }
        init(i,s); 
    }
    for(long long i=1;i<=ans[1];i++) dp[1][i]=1;
//    for(long long i=1;i<=m;i++)
//    {
//        cout<<ans[i]<<endl;
//        for(long long j=1;j<=ans[i];j++) cout<<s[i][j]<<" ";
//        system("pause");
//    }
//         
    for(long long i=2;i<=m;i++)
    {
        for(long long j=1;j<=ans[i];j++)
        {
            for(long long k=1;k<=ans[i-1];k++)
            {
//                cout<<i<<" "<<j<<" "<<k<<" "<<s[i][j]<<" "<<s[i-1][k]<<endl;
                if(s[i][j]&s[i-1][k]) continue;
//                if((s[i][j]>>1)&s[i-1][k]) continue;
//                if((s[i][j]<<1)&s[i-1][k]) continue;
                dp[i][j]+=dp[i-1][k]%mod; 
            }
        }
    }
    long long sum=0;
    for(long long i=1;i<=ans[m];i++) sum+=dp[m][i]%mod,sum%=mod;
    cout<<sum%mod;
}
View Code

相关文章: