10817 - Headmaster's Headache (状压dp)

题目链接: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
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值