题目链接:uva 10817
题意:
某个学校师资力量不够,要招收新的老师,第一行给出s、m、n,现在在任的老师有m个,然后给出m行表示每个老师的信息,分别是该老师的工资,以及可教授的课程(个数不一定),然后在n行表示可招收的老师信息,同样是工资和课程,s表示该学校开售的课程,问,最少花多少钱可以使得该学校开设的s个课程每个课程至少有两个老师任教。
ps:现任的老师全部交,一个老师不管交多少课程,工资都是那些。
思路:
三进制状压dp,先求出现任老师的状态,然后预处理每个预招老师的状态,然后类似分组背包即可。不过得注意的是求状态的时候不能有进位操作产生,因为一个课程也可以有多个老师交,而这一位的状态应该还是2,卡了我好久。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 20005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;
int n,m,ans,cnt,tot,flag;
int s,state,cost,dp[10000],fac[10];
int w[105],ss[105];
char cs[100];
void solve()
{
int i,j,t;
memset(dp,0x3f,sizeof(dp));
for(i=0;i<fac[s];i++)
{
int flg=1;
for(int k=0;k<s;k++)
{
if((i/fac[k])%3>(state/fac[k])%3) flg=0;
}
if(flg) dp[i]=cost;
}
for(j=1; j<=n; j++)
{
for(i=fac[s]-1; i>=0; i--)
{
int x=0;
for(int k=0;k<s;k++)
{
t=max(0,(i/fac[k])%3-(ss[j]/fac[k])%3);
x+=t*fac[k];
}
dp[i]=min(dp[i],dp[x]+w[j]);
}
}
ans=dp[fac[s]-1];
}
int main()
{
int i,j,t;
fac[0]=1;
for(i=1; i<=8; i++)
{
fac[i]=fac[i-1]*3;
}
while(~scanf("%d%d%d",&s,&m,&n))
{
if(s==0) break ;
gets(cs);
state=cost=0;
for(i=1; i<=m; i++)
{
gets(cs);
cnt=t=0;
for(j=0; ; j++)
{
if(cs[j]>='0'&&cs[j]<='9')
{
t=t*10+cs[j]-'0';
}
else
{
if(t)
{
cnt++;
if(cnt==1) cost+=t;
else
{
if((state/fac[t-1])%3<2) state+=fac[t-1];
}
t=0;
}
if(cs[j]=='\0') break ;
}
}
}
for(i=1; i<=n; i++)
{
gets(cs);
cnt=t=ss[i]=0;
for(j=0; ; j++)
{
if(cs[j]>='0'&&cs[j]<='9')
{
t=t*10+cs[j]-'0';
}
else
{
if(t)
{
cnt++;
if(cnt==1) w[i]=t;
else ss[i]+=fac[t-1];
t=0;
}
if(cs[j]=='\0') break ;
}
}
}
solve();
printf("%d\n",ans);
}
return 0;
}
/*
2 2 3
10000 1
20000 2
2000 1
40000 1 2
300 2
2 2 2
10000 1 2
20000 2 1
30000 1 2
40000 1 2
0 0 0
*/