题意:s个学科,每个学科至少要2个老师教,现有m个老师,不能辞退他们的前提下,从n个应聘者招收若干个使得每个学科至少2个老师教,求总工资的最小值。
思路:dp[i][j]中的i表示科目被选的状态,j表示多于1个人选择某科目的状态,dp[(1<<s)-1][(1<<s)-1]即为答案。
# include <bits/stdc++.h> # define INF 0x3f3f3f3f using namespace std; int dp[1<<8][1<<8], sta[101], cost[101], num[10], sta1, sta2, sum, s, m, n, tmp;; int solve() { int up = (1<<s)-1; memset(dp, INF, sizeof(dp)); dp[sta1][sta2] = sum; for(int i=0; i<n; ++i) for(int j=up; j>=0; --j) for(int k=up; k>=0; --k) { if(dp[j][k] == INF) continue; int nsta1 = (j|sta[i]); int nsta2 = (j&sta[i])|k; dp[nsta1][nsta2] = min(dp[nsta1][nsta2], dp[j][k] + cost[i]); } return dp[up][up]; } int main() { char str[100]; while(~scanf("%d%d%d",&s,&m,&n)&&s) { memset(sta, 0, sizeof(sta)); memset(cost, 0, sizeof(cost)); memset(num, 0, sizeof(num)); sta1 = sta2 = sum = 0; while(m--) { scanf("%d",&tmp); gets(str); int len = strlen(str); for(int i=0; i<len; ++i) if(isdigit(str[i])) { int no = str[i]-'0'; sta1 |= 1<<(no-1); ++num[no-1]; } sum += tmp; } for(int i=0; i<s; ++i) if(num[i] >= 2) sta2 |= (1<<i); for(int i=0; i<n; ++i) { scanf("%d",&cost[i]); gets(str); int len = strlen(str); for(int j=0; j<len; ++j) if(isdigit(str[j])) { int no = str[j]-'0'; sta[i] |= 1<<(no-1); } } printf("%d\n",solve()); } return 0; }