初始的为正,最后的为负,假设我们能找到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<<22using 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 100000000int 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 70000ll 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 70000using 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;}