写了几道状压。。。然后就一直在颓废。。。
2064: 分裂
http://www.lydsy.com/JudgeOnline/problem.php?id=2064
初始的为正,最后的为负,假设我们能找到k组凑成0的话,答案就是n+m-2*k。于是状压。。其实我一点都不会。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define maxn 1<<22
using
namespace
std;
int
t,mm,f[maxn],sum[maxn],ans,n,m,a[50],b[50];
int
main(){
scanf
(
"%d"
,&n);
rep(i,0,n-1)
scanf
(
"%d"
,&a[i]);
scanf
(
"%d"
,&m);
rep(i,0,m-1)
scanf
(
"%d"
,&b[i]);
rep(i,0,n-1) sum[1<<i]=a[i];
rep(i,n,n+m-1) sum[1<<i]=-b[i-n];
mm=1<<(n+m);
rep(i,1,mm-1){
t=i&(-i);
sum[i]=sum[t]+sum[i-t];
rep(j,0,m+n-1)
if
((1<<j)&i) f[i]=max(f[i],f[i^(1<<j)]);
if
(!sum[i]) ++f[i];
}
printf
(
"%d\n"
,n+m-2*f[mm-1]);
return
0;
}
1725: [Usaco2006 Nov]Corn Fields牧场的安排
http://www.lydsy.com/JudgeOnline/problem.php?id=1725
f[i][j]表示第i行,情况是j的答案。于是裸状压。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define maxn 5000
#define mm 100000000
int
y,sum,tot,ans,ff[20][maxn],f[20][maxn],g[20][maxn],d[maxn],map[20][20],n,m;
using
namespace
std;
void
dfs(
int
x){
if
(x>m) {
d[y]=++tot;
g[y][tot]=sum;
ff[y][tot]=ans;
return
;
}
if
(map[y][x]==1){
sum+=(1<<(x-1));
ans++;
dfs(x+2);
sum-=(1<<(x-1));
ans--;
}
dfs(x+1);
}
int
main(){
scanf
(
"%d%d"
,&n,&m);
rep(i,1,n)
rep(j,1,m)
scanf
(
"%d"
,&map[i][j]);
rep(i,1,n){
tot=ans=sum=0;
y=i;
dfs(1);
}
ans=0;
if
(n==1)
printf
(
"%d\n"
,d[1]);
else
{
rep(i,1,d[1]) f[1][i]=1;
rep(i,2,n)
rep(j,1,d[i])
rep(k,1,d[i-1]){
if
((g[i][j]&g[i-1][k])==0) f[i][j]=(f[i][j]+f[i-1][k])%mm;
}
rep(i,1,d[n]) ans=(ans+f[n][i])%mm;
printf
(
"%d"
,ans);
}
return
0;
}
1231: [Usaco2008 Nov]mixup2 混乱的奶牛
http://www.lydsy.com/JudgeOnline/problem.php?id=1231
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define ll long long
#define maxn 70000
ll f[maxn][20],mm,ans;
int
n,m,a[20];
int
main(){
scanf
(
"%d%d"
,&n,&m);
rep(i,1,n)
scanf
(
"%d"
,&a[i]);
rep(i,0,n-1) f[1<<i][i+1]=1;
mm=(1<<n)-1;
rep(i,0,mm)
rep(j,1,n)
if
(1<<(j-1)&i)
rep(k,1,n)
if
((1<<(k-1)|i)!=i&&
abs
(a[k]-a[j])>m) f[i|1<<(k-1)][k]+=f[i][j];
rep(i,1,n) ans+=f[mm][i];
printf
(
"%lld\n"
,ans);
return
0;
}
2073: [POI2004]PRZ
http://www.lydsy.com/JudgeOnline/problem.php?id=2073
主要就是枚举子集转移的时候比较神奇。其实也没什么。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define ll long long
#define maxn 70000
using
namespace
std;
int
mm,n,m,a[20],b[20],t[20],w[maxn],tim[maxn],f[maxn];
int
main(){
scanf
(
"%d%d"
,&m,&n);
rep(i,1,n)
scanf
(
"%d%d"
,&a[i],&b[i]),t[i]=1<<(i-1);
mm=(1<<n)-1;
rep(i,0,mm)
rep(j,1,n)
if
(t[j]&i) tim[i]=max(tim[i],a[j]),w[i]+=b[j];
memset
(f,127/3,
sizeof
(f)); f[0]=0;
rep(i,1,mm)
for
(
int
j=i;j;j=i&(j-1))
if
(w[j]<=m) f[i]=min(f[i],tim[j]+f[i^j]);
printf
(
"%d\n"
,f[mm]);
return
0;
}