uva 10817Headmaster's Headache

来源:互联网 发布:安徽中港金融数据 编辑:程序博客网 时间:2024/05/29 07:19

原题:
The headmaster of Spring Field School is considering employing some new teachers for certain subjects.
There are a number of teachers applying for the posts. Each teacher is able to teach one or more subjects. The headmaster wants to select applicants so that each subject is taught by at least two
teachers, and the overall cost is minimized.
Input
The input consists of several test cases. The format of each of them is explained below: The first line contains three positive integers S, M and N. S (≤ 8) is the number of subjects, M(≤ 20) is the number of serving teachers, and N (≤ 100) is the number of applicants. Each of the following M lines describes a serving teacher. It first gives the cost of employing him/her (10000 ≤ C ≤ 50000), followed by a list of subjects that he/she can teach. The subjects are numbered from 1 to S. You must keep on employing all of them. After that there are N lines, giving the details of the applicants in the same format.
Input is terminated by a null case where S = 0. This case should not be processed.
Output
For each test case, give the minimum cost to employ the teachers under the constraints.
Sample Input
2 2 2
10000 1
20000 2
30000 1 2
40000 1 2
0 0 0
Sample Output
60000

中文:
给你三个数s,m,n
分别表示有多少门课,有多少个在职教师,有多少个应聘教师
然后给你n+m行,每行有每个老师的工资和能教的课

现在要求每门课至少有两个老师教,每个老师可以教多门课,在职教师不能辞退,问你在满足每门课最少两个老师的情况下,需要花多少钱来雇佣老师

#include<bits/stdc++.h>using namespace std;const int maxn=1<<8;int dp[150][maxn][maxn];int n,m,s,st[150],c[150];const int inf=121*50000;int dfs(int i,int s0,int s1,int s2){    if(i==m+n)    {        return s2==(1<<s)-1 ? 0 : inf;    }    int& ans=dp[i][s1][s2];    if(ans>=0)        return ans;    ans=inf;    if(i>=m)        ans=dfs(i+1,s0,s1,s2);    int m0=st[i]&s0,m1=st[i]&s1;    s0^=m0;    s1=(s1^m1)|m0;    s2|=m1;    ans=min(ans,c[i]+dfs(i+1,s0,s1,s2));    return ans;}int main(){    ios::sync_with_stdio(false);    string line;    while(cin>>s>>m>>n)    {        cin.ignore();        if(s==0)            return 0;        memset(dp,-1,sizeof(dp));        memset(st,0,sizeof(st));        for(int i=0;i<n+m;i++)        {            string tmp;            int res;            getline(cin,tmp);            stringstream ss(tmp);            ss>>c[i];            while(ss>>res)            {                st[i]|=(1<<(res-1));            }            //cout<<st[i]<<endl;        }        int ans=dfs(0,(1<<s)-1,0,0);        cout<<ans<<endl;    }    return 0;}

解答:

紫书上面的例题,而且还附有代码~

首先从数据上来看,就能看出此题需要用状态压缩的方法来解决。
在不考虑每门课至少有两个老师教且没有在职教师的情况下,状态转移方程是这样
dp[s]=min(dp[s-{Appi}]+money[i])
其中s用状态压缩的方法来表示每门课是否有人教,{Appi}表示应聘者i能教授的课程

但是,如果考虑题目中的要求,很容易想到要保存每门课的状态S,而且这个S最好还能看出来每门课有多少人教授。如此下来,可以想到设置状态dp[S][i]表示每门课在状态S的情况下,选取到前i个应聘者最少花费的钱数。
但是,关键在于这个课的状态S如何才能表示每个课有多少人教?

考虑极限数据情况,有100个应聘者,算上在职教师有120个,假设每个老师都能教最多的8个课程,那么有2^(120×8)个状态。 明显不可能

在紫书当中,处理的很巧妙,使用两个状态,s1和s2,分别为只有一个人教课的状态和大于等于两个人教课的状态,如此下来,不需要考虑多余两个人教课的科目有多少人~ 这样就实现了状态的定义

状态压缩的转移方程还是很好想的,看代码就能明白了