【模板】状压DP

**[POI2004]PRZ**

**考察内容:二进制子集遍历,DP转移**

#include <bits/stdc++.h>
using namespace std;

int n,W;
struct data1 {
	int t,w;
}a[20];

int dp[(1<<20)],tt[(1<<20)],ww[(1<<20)];

int main() {
	scanf("%d%d",&W,&n);
	for(int i=1;i<=n;i++) {
		scanf("%d%d",&a[i].t,&a[i].w);
	}
	
	int lim=(1<<n);
	for(int i=0;i<lim;i++) {
		for(int j=0;j<n;j++) {
			if((i>>j)&1) {
				tt[i]=max(tt[i],a[n-j].t);
				ww[i]+=a[n-j].w;
			}
		}
	}
	
	memset(dp,0x3f,sizeof dp);
	dp[0]=0;
	
	for(int i=0;i<lim;i++) {
		for(int j=i;j>=0;j=i&(j-1)) {
			if(ww[i^j]<=W) {
				dp[i]=min(dp[i],dp[j]+tt[i^j]);
			}
			if(!j) break;	
		}
	}
	printf("%d",dp[lim-1]);
	return 0;
}
**互不侵犯**

**考察内容:状态矛盾处理,DP转移**

#include <bits/stdc++.h>
using namespace std;
#define LL long long
int n,k;
LL dp[10][(1<<10)][100];

bool checkself(int x) {
	if((x<<1) & x) return 0;
	else return 1;
}

bool check(int x,int y) {
	if(x & y) return 0;
	else if((x<<1) & y) return 0;
	else if((x>>1) & y) return 0;
	else return 1;
}

int main() {
	scanf("%d%d",&n,&k);
	dp[0][0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int x=0;x<(1<<n);x++)
		{
			if(!checkself(x)) continue;
			for(int y=0;y<(1<<n);y++) 
			{
				if(!checkself(y)) continue;
				if(check(x,y)) 
				{
					int numx=__builtin_popcount((unsigned)x);
					for(int j=k;j>=numx;j--) {
						dp[i][x][j]+=dp[i-1][y][j-numx];
					}
				}
			}	
		}
	}
	LL ans=0;
	for(int i=0;i<(1<<n);i++) {
		ans+=dp[n][i][k];
//		printf("%d ",dp[n][i][k]);
	}
	printf("%lld",ans);
	return 0;
}
posted on 2024-11-21 12:47  Ueesugi_sakura  阅读(2)  评论(0编辑  收藏  举报