UVA10817 校长的烦恼 Headmaster‘s Headache

22 篇文章 0 订阅
  • 题意校长的烦恼 Headmaster’s Headache
  • s很小,不难想到用状态压缩处理。但是我对状态压缩的应用还是固守在了处理棋盘上,一开始想的是把每门学科用两位二进数表示,但是没法做状态转移。
  • 正解:用两个二进数表示当前状态,第一个数s1表示恰有一个人教的学科集合(某一位为0表示不在集合中,某一位为1表示在集合中),另一个数表示至少有两个人教的学科的集合,d(i,s1,s2)表示已经考虑了前i-1个人时(前i-1人聘用情况确定即s1s2确定,后面人的聘用情况任意)此状态下的最小花费,答案为d(1,0,0),为方便计算同时维护当前的未教课程集合s0。
  • 代码(紫书上的记忆化搜索写法特别好)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=(1<<8)+8,inf=5e7 ;
int s,m,n,d[125][maxn][maxn],st[125],sub,c[125],num; //st:每个教师所能教授的学科 
char cc;
int dp(int nw,int s0,int s1,int s2)
{
	if(nw==n+m+1) return s2==(1<<s)-1?0:inf;
	int& ans = d[nw][s1][s2];//引用 
	if(ans>=0) return ans;//-1表示未计算 
	ans = nw>m?dp(nw+1,s0,s1,s2):inf;//不选i 
	int m0 = s0&st[nw],m1 = s1&st[nw];
	s0^=m0;s1=(s1^m1)|m0;s2|=m1;//状态更新 
	ans=min(ans,c[nw]+dp(nw+1,s0,s1,s2));//选i 
	return ans;
	
}
void intt()
{
	for(int i=1;i<=num;i++)
	for(int j=0;j<maxn;j++)
	for(int k=0;k<maxn;k++)
	d[i][j][k]=-1;
}
int main()
{
	while(cin>>s>>m>>n)
	{
		if(!s) return 0;
		num=n+m;
		intt();
		for(int i=1;i<=num;i++)
		{
			int ans=0;
			scanf("%d",&c[i]);
			cc=getchar();
			while(cc!='\n')
			{
				if(cc!=' ')
				ans+=(1<<((cc-48)-1));
				cc=getchar();
			}
			st[i]=ans;
		}
		cout<<dp(1,(1<<s)-1,0,0)<<endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈希表扁豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值