两个月前AC过的一道DP题.现在发现了一个复杂度较低的算法了~贴上两次AC的代码比较一下吧.
--------------------------------------以前的--------------------------------------------
以下标i表示barn的每一种状态. 从低位向高位,第k位为1表示第k个barn未被占用,(0<=k<=m-1)
dp[i]=num表示另barn的状态为i的方法有num种
结果就是sum{dp[i]} (0<=i<=(1<<m)-1)
基本上是对每头牛扫描一遍全部状态,判断每个状态的任意一个barn是否可分配.复杂度是n*m*2^m
Problem Id:2441 User Id:ecchi
Memory:4156K Time:388MS
Language:C++ Result:Accepted
Source
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
int dp[0x100000];
int cow[20];
int op[20];
int n,m;
int main()
{
// freopen("1.in","r",stdin);
scanf("%d %d",&n,&m);
int valid=(1<< m)-1;
int bn;
int i,j,k;
for(i=0;i< m;++i){
op[i]=1<< i;
}
int pos;
memset(dp,0,0x400000);
dp[valid]=1;
memset(cow,0,20);
for(i=0;i< n;++i){
scanf("%d",&bn);
for(j=0;j< bn;++j){
scanf("%d",&pos);
cow[i]|=1<< (pos-1);
}
}
int buf;
int count=0;
int out;
for(i=0;i< n;++i){
for(j=0;j< =valid;++j){
buf=j&cow[i];
if(dp[j]&&buf){
for(k=0;k< m;++k){
if(buf&op[k]){
dp[j^op[k]]+=dp[j];
}
}
}
dp[j]=0;
}
}
dp;
int sum=0;
for(i=0;i< =valid;++i){
sum+=dp[i];
}
printf("%d/n",sum);
return 0;
}
-----------------------------------------现在的--------------------------------------------
以下标i表示barn的每一种状态. 从低位向高位,第k位为1表示第k个barn未被占用,(0<=k<=m-1)
dp[i]=num表示另barn的状态为i的方法有num种
结果就是sum{dp[i]} (0<=i<=(1<<m)-1&& i的二进制位中0的个数为n)
从(1<<m)-1到0,对每一个barn状态算出0的个数,即为当前要处理的牛的号码,再判断任意一个barn是否可以分配.可以看到这样做的复杂度是(2^m)*m (算0的个数时间上<=m),直接少了个n.不过常数会比较大,m,n<=20的情况下,效率不见得会有很大改进.
Problem Id:2441 User Id:ecchi
Memory:4148K Time:139MS
Language:GCC Result:Accepted
Source
#include "stdio.h"
#include "string.h"
int dp[0x100000];
int main()
{
// freopen("1.in","r",stdin);
int n,m;
int cow[20];
int op[20];
memset(cow,0,80);
memset(op,0,80);
scanf("%d %d",&n,&m);
int valid=(1<< m)-1;
int bn;
int i,j,k;
for(i=0;i< m;++i){
op[i]=1<< i;
}
int pos;
dp[valid]=1;
for(i=0;i< n;++i){
scanf("%d",&bn);
for(j=0;j< bn;++j){
scanf("%d",&pos);
cow[i]|=1<< (pos-1);
}
}
int dpbuf;
int buf;
int count;
int sum=0;
for(i=valid;i>=0;--i){
dpbuf=dp[i];
if(dpbuf==0){
continue;
}
buf=i;
count=0;
while(buf>0){
++count;
buf&=(buf-1);
}
count=m-count;
if(count>=n){
if(count==n){
sum+=dpbuf;
}
continue;
}
buf=i&cow[count];
if(dpbuf&&buf){
for(k=0;k< m;++k){
if(buf&op[k]){
dp[i^op[k]]+=dpbuf;
}
}
}
}
printf("%d/n",sum);
return 0;
}
-----------------------------------------------总结下------------------------------------------------
较之后面的算法,第一种算法效率较低,在于没有利用好barn状态同时也能反映牛的处理情况的特性.
多了一层n的循环