Uva 10817 Headmaster's Headache (DP+ 状态压缩)

来源:互联网 发布:扒皮吧软件 编辑:程序博客网 时间:2024/06/05 21:48

Problem D: Headmaster's Headache

Time limit: 2 seconds

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 andN. 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 210000 120000 230000 1 240000 1 20 0 0

Sample Output

 

60000

 

 

题意:有一个学校想要聘请老师,要求每个学科都有两个以上的老师授课,并且要使总

费用最小。有S(最多8个)个学科,现任的M(最多20个)个老师(你必须继续聘请他
们),N(最多100个)份申请。后来的M行每行有至少两个整数,表示现任的老师的工
资,和他所教授的课程(可能不止一个)。再后来的N行每行有也有至少两个整数表示
聘请这个老师所需的费用,以及他所教授的课程(可能不止一个)。

思路:因为要使每个学科都有两个以上的老师授课,所以不能用普通二进制表示。即可

以将每门学科的上课情况用二位二进制数表示。

即  将八位扩充为16位  具体细节看代码。

 

#include <iostream>#include <cstdio>#include <cstring>#include <climits>#include <sstream>#include <string>#include <vector>using namespace std;const int inf=INT_MAX;const int M=110;const int N=16;vector <int> G[M];int dp[M][1<<N],cost[M];int s,n,m,num,sum,len;void initial(){    len=1<<(2*s);    for(int i=0;i<=n;i++)        for(int j=0;j<len;j++)             dp[i][j]=inf;    for(int i=0;i<=n;i++)  G[i].clear();    sum=num=0;}void input(){    string str;    int x;    getchar();    for(int i=0;i<m;i++)    {         getline(cin,str);         stringstream ss(str);         ss>>x;         sum+=x;         while(ss>>x)         {              int one=2*x-2,two=2*x-1;              if(num & 1<<one)  num |=(1<<two);              else num |= (1<<one);         }    }    for(int i=1;i<=n;i++)    {         getline(cin,str);         stringstream ss(str);         ss>>cost[i];         while(ss>>x)  G[i].push_back(x);    }}bool judge(int p,int q){    for(int i=0;i<G[q].size();i++)    {         int one=2*G[q][i]-2,two=2*G[q][i]-1;         if(!(p & 1<<one)  || !(p & 1<<two))  return  true;    }    return false;}void solve(){    dp[0][num]=sum;    for(int i=1;i<=n;i++)        for(int j=0;j<len;j++)        {             dp[i][j]=min(dp[i][j],dp[i-1][j]);             if(dp[i-1][j]==inf)  continue;             if(judge(j,i))             {                  int t=j;                  for(int k=0;k<G[i].size();k++)                  {                       int one=2*G[i][k]-2,two=2*G[i][k]-1;                       if(t & 1<<one)  t |=(1<<two);                       else t |= (1<<one);                  }                  dp[i][t]=min(dp[i][t],dp[i-1][j]+cost[i]);             }        }    printf("%d\n",dp[n][len-1]);}int main(){    while(scanf("%d %d %d",&s,&m,&n)!=EOF)    {         if(s==0)  break;         initial();         input();         solve();    }    return 0;}


 

 

 

0 0
原创粉丝点击