uva 10817 - Headmaster's Headache 校长的烦恼


题目:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=465&page=show_problem&problem=1758


显而易见的背包问题+集合动归


关键是集合不是一般的集合,每门课的状态有三种:没有老师,有了1个老师,有两个及以上。


1.我的办法是用3进制数表示


2.看了别人的题解

dp[state1][state2],只有当state1里面对应位置被填充了,才能填充state2


nextS1 = p[i] | s1,

nextS2 = (p[i] & s1) | s2

f[nextS1][nextS2] = min(f[nextS1][nextS2], f[s1][s2] + p[i])


感觉这种方非常简便。


但是他这种做法的时间复杂度比我要高一点。因为 2^8*2^8=65 536>3^8=6 561

他的状态比我多一些。


/**==========================================
 *   This is a solution for ACM/ICPC problem
 *
 *   @source: uva 10817 Headmaster¡¯s Headache
 *   @type:  dp
 *   @author: wust_ysk
 *   @blog:  http://blog.csdn.net/yskyskyer123
 *   @email: 2530094312@qq.com
 *===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<sstream>
#include<vector>
#define ysk(x)  (1<<(x))
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 120   ;
//const int maxV=12    ;
int sub,m,n;
string s;
int sal[maxn+5];
vector<int> ab[maxn+5];
const int maxed= 6561-1;//3^8
int fac[]={1,3,9,27,81,243,729,2187,6561};
int dp[ maxed+5],ed;
int  get(int s,int x)
{
    s/=fac[x];
    return s%3;
}


int addst(int  s,int x)
{
    int num=get(s,x);
    if(num==2)  return s;
    s+=fac[x];
    return s;
}
int main()
{
    int x;
    while(~scanf("%d%d%d",&sub,&m,&n)&&(m+n+sub))
    {
        getchar();
        int st=0,ret=0;
        ed=fac[sub]-1;
        for(int i=1;i<=m+n;i++)
        {
            getline(cin,s);
            stringstream ss(s);
            ss>>sal[i];
            if(i<=m)  ret+=sal[i];
            ab[i].clear();

            while(ss>>x)
            {
                x--;
                ab[i].push_back(x);
                if(i<=m) st=addst( st,x);
            }

        }
        memset(dp,0x3f,fac[sub] *sizeof dp[0]);
        dp[st]=ret;
        for(int i=m+1;i<=m+n;i++)
        {
            for(int s=ed;s>=st;s--)
            {
                int s2=s;
                for(int j=0;j<ab[i].size();j++)
                {
                    int x=ab[i][j];
                    s2=addst(s2,x);
                }
                dp[s2]=min(dp[s2],dp[s]+sal[i]);
            }
        }
        printf("%d\n",dp[ed]);


    }


   return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值