UVA - 10817 Headmaster's Headache 状态压缩

来源:互联网 发布:php qq在线客服代码 编辑:程序博客网 时间:2024/09/21 11:14

题目大意:有S种课程,M个在职老师,N个求职老师,每个老师都有相应的工资,在职老师不能辞退,要求每种课程至少要有两个老师教,每个老师都有自己的一系列教学课程,要求在S种课程至少有2个老师教的情况支付的工资最少

解题思路:这题和以前的状态压缩的状态不一样,以前的状态只有两种,0或1,这里的状态变成了三种,0,1,2,那就仿照以前的做法,设置一个状态,只不过这个状态是3进制的就对了,然后按照每个老师的能力去匹配。状态转移方程为,f[i][j] = max(f[i-1][j],f[i-1][k] + p[i]),i表示前i个求职老师,j表示当前状态,k表示前一个状态,p[i]表示第i个求职老师的工资,k状态下+第j个老师的教学课程 == 当前状态

这里的状态不一样了,(假设end为每位都为2)不能以end为最终状态了,而应该以0为最终状态,为什么不能以end为最终状态,因为在匹配教师的能力时需要找到前一个状态,而前一个状态的量比较多,比如这个老师可以教1,3,4三种课程,假设当前这个状态下第1,3,4位刚好是2,那么前一个状态该怎么表示呢,前一个状态就有很多了,1,3,4位可以都为1,那么就表示因为这个老师的缘故,所以1,3,4状态都变成了2了,1,3,4位也可以为2,表示这三种课程不需要这个老师教,那么当前状态的前一个状态就有8种了,所以以end为最终状态比较难表示。那就以0表示最终状态了,那么每位上的数字的含义就变了,每位的数字就表示当前课程还需要多少个老师,具体看代码

#include<cstdio>#include<cstring>#include<ctype.h>using namespace std;#define maxn 110#define maxm 10010#define INF 0x3f3f3f3fint dp[maxn][maxm],f[maxm][maxn],p[maxm],les[maxn];int S,M,N,V,temp[maxn];char str[maxn];int init() {gets(str);sscanf(str,"%d%d%d",&S,&M,&N);if(S + M + N == 0)return 0;int len ,t;V = 0;//没个课程初始为2for(int i = 1; i <= S; i++)les[i] = 2;//servering teachersfor(int i = 1; i <= M; i++) {gets(str);len = strlen(str);sscanf(str,"%d",&t);V += t;//所有在职的老师的工资总和int j = 0;while(isdigit(str[j]))j++;for(++j; j < len; j++) {sscanf(&str[j],"%d",&t);if(les[t])les[t]--;while(isdigit(str[j]))j++;}}memset(f,0,sizeof(f));//applicants for(int i = 1; i <= N; i++) {gets(str);len = strlen(str);sscanf(str,"%d",&t);p[i] = t;//每个老师的工资int j = 0;while(isdigit(str[j]))j++;for(++j; j < len; j++) {sscanf(&str[j],"%d",&t);f[i][t] = 1;//所能教的课程while(isdigit(str[j]))j++;}}return 1;}void solve() {memset(dp,0x3f,sizeof(dp));int end = 0;//状态量,因为每个课程要两个老师,所以乘3for(int i = 1; i <= S; i++)end = end * 3 + 2;for(int i = 0; i <= end; i++) {int t = i;//i状态下的课程for(int j = 1; j <= S; j++) {temp[j] = t % 3;t = t / 3;}int j ;//初始化,i状态能用0-M个在职教师的教学课程表示,在职教师不一定要每节课都教,因为每个在职教师能辞退,所以一定要为Vfor(j = 1; j <= S && temp[j] >= les[j] ;j++);if(j == S + 1)dp[0][i] = V;//V表示的是在职教师教授所有课程的状态,如果前一个状态}for(int i = 1 ; i <= N; i++) for(int j = 0; j <= end; j++) {dp[i][j] = dp[i-1][j];int t = j;for(int k = 1; k <= S; k++) {temp[k] = t % 3;t = t / 3;}for(int k = 1; k <= S; k++) {//找寻每一位的前一个状态if(f[i][k] && temp[k] < 2)temp[k]++;}t = 0;for(int k = S; k >= 1; k--)t = t * 3 + temp[k];if(dp[i][j] > dp[i-1][t] + p[i])dp[i][j] = dp[i-1][t] + p[i];}printf("%d\n",dp[N][0]);}int main() {for(;;) {if(!init())return 0;solve();}}



0 0
原创粉丝点击