UVA-10817- Headmaster's Headache
题意:
这间学校开设S门课,给出校长已经有的师资n,然后再给出m个应聘者,每门课至少有两名任课老师,求最少需要的雇佣工资。
分析:
这个题的输入很奇怪,每个人的信息输入在一行上,不能简单地读取,需要用字符串处理操作。
已经有的师资是肯定要的,而对于求职者可以要可以不要,第一纬度状态就是当前的人,如果第二维度是开设的开设的课程的话,那么要把有一个老师任课的课程和有两个老师以上任课的课程都作为状态。
- 位运算操作很重要,状压dp中状态转移,集合之间的交并集的处理很关键。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 130;
const int INF = 1<<20;
int s,m,n,x;
int d[maxn][1<<8][1<<8];
int c[maxn],st[maxn];
int dp(int i,int s0,int s1,int s2)
{
if(i==m+n)
return s2 == (1<<s)-1 ? 0:INF;
int &ans = d[i][s1][s2];
if(ans>=0) return ans;
ans = INF;
if(i>=m)//不选当前求职者
ans = dp(i+1,s0,s1,s2);
int m0 = st[i] & s0;//没人讲的课中i可以讲的
int m1 = st[i] & s1;//有一个人讲的课中,i可以讲的
s0 ^= m0;//把s0中消去i讲的
s1 = (s1 ^ m1) | m0;//把s1中去除i讲的m1,添加i讲的m0
s2 |= m1;//添加i讲的m1到s2集合
ans = min(ans,c[i]+dp(i+1,s0,s1,s2));
return ans;
}
int main()
{
string str;
while(getline(cin,str))
{
memset(st,0,sizeof st);
//下面是字符串流操作,每次输入一行的内容到str
stringstream ss(str);
ss>>s>>m>>n;
if(s==0)
break;
for(int i=0;i<m+n;i++)
{
getline(cin,str);stringstream ss(str);
ss>>c[i];
while(ss>>x)
st[i] |= 1<<(x-1);
}
memset(d,-1,sizeof d);
int ans = dp(0,(1<<s)-1,0,0);
cout<<ans<<endl;
}
return 0;
}