【状压dp】校长的烦恼UVA10817

又是一道看题就懵逼抄题解的题

每个状态可以用三个集合表示,没有人教科目集,只有一个人教科目集,至少两人教科目集,可以发现任意两个集合可以推出来第三个,为了方便我选了前两个

然后另一维是当前已经对前i个老师做完决策了,对每个老师有选和不选两种决策,但是前M个必须选。

所以当没人教科目集和只有一人教科目集为空集时和所有老师都考虑完时为边界

怒交一发,不出意外又WA。然后看了一眼debug不过的数据发现,有一种情况是固定教师还没考虑完时已经到边界可以返回零了,但这时要继续向下知道所有固定教师都考虑完,无论他们是否有用都必须聘用

这个读入也是贼坑了,getsCE,只能一个字符一个字符读

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#define INF (21000010)
using namespace std;
int S,M,N,T[2020],val[2020],A[2020],dp[125][(1<<8)+5][(1<<8)+5];
bool vis[125][(1<<9)+5][(1<<9)+5];
void InIt(){
	memset(T,0,sizeof(T));
	int i,x=0; char ch;
	while (1){
		ch=getchar();
		if (ch=='\n') break;
		if (ch!=' ') x=(x<<3)+(x<<1)+ch-'0';
		else if (x) T[++T[0]]=x,x=0;
	}
	if (x)  T[++T[0]]=x;
}
int Dfs(int i,int s0,int s1){
	int &ans=dp[i][s0][s1];
	if (vis[i][s0][s1]) return ans;
	vis[i][s0][s1]=1;
	if (!s0&&!s1&&i>M) return ans=0;
	//坑点,此处不能直接退,因为固定教师一定要用 
	if (i==N+M+1) return ans=INF;
	
	if (i>M) ans=min(ans,Dfs(i+1,s0,s1));
	int m0=A[i]&s0,m1=A[i]&s1;
	//m0:能使没人教变成有一个人教的科目集合 
	//m1: 能使一个人教变成至少两个人教的科目集合 
	s0^=m0; s1^=m1; s1|=m0; 
	ans=min(ans,Dfs(i+1,s0,s1)+val[i]);
	return ans;
}
void Work(){
	int i,j;
	memset(A,0,sizeof(A));
	memset(vis,0,sizeof(vis));
	memset(dp,127/3,sizeof(dp));
	for (i=1;i<=M+N;i++){
		InIt();
		val[i]=T[1];
		for (j=2;j<=T[0];j++) A[i]|=(1<<(T[j]-1));
	}
	printf("%d\n",Dfs(1,(1<<S)-1,0));//写成(1<<M)-1 
}
int main(){
	while (1){
		scanf("%d %d %d",&S,&M,&N);
		if (!S&&!M&&!N) break;
		char ch=0;
		while (ch!='\n') ch=getchar();
		Work();
	}
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值