UVA 10817 Headmaster's Headache

题目大意:有一个学校要招老师,给你s门课,m个现役的老师,给你这m个老师分别教哪些课和他们的cost,现役的老师必须要继续留着,然后再给你n个应聘者,分别给你这n个人教哪些课和他们的cost,现在要求每门课至少要有两个老师教,问你最少的cost。

思路:基础的三进制的状态压缩DP吧,基本思想和二进制一样,只是这里需要多处理一下,用num[ i ][ j ] 表示数 i 如果用三进制表示,那么第 j 位为多少,设d[ s ] 表示状态s的最少花费,那么d[ s|si ] = min(d[ s ] +cost[ i ])。

在这里吐槽一下,这道题读入数据有点坑,没告诉你课的数目,我用的是先字符串读进去,再一个一个抠。。 = =

代码如下:

#include
#include
#include
using namespace std;

const int INF = 0x0fffffff ;

int my_pow(int x)
{
    int s = 1;
    for(int i =1;i<=x;i++)
        s *= 3;
    return s;
}

int num[22222][11];

void init()
{
    memset(num,0,sizeof(num));
    int s = my_pow(9);
    for(int i = 1;i=3)
            s += 2*tmp;
        else s += (num[x][i]+num[y][i])*tmp;
        tmp *= 3;
    }
    return s;
}

int d[22222] ;

char str[111];

int main()
{
    init();
    int s,m,n;
    while(~scanf("%d%d%d",&s,&m,&n)&&s)
    {
        getchar();

        int S = my_pow(s)-1;

        for(int i = 0;i<=S;i++)
            d[i] = INF;

        int S0 = 0;
        int sum = 0;
        for(int i = 1;i<=m;i++)
        {
            gets(str);
            for(int j = 0;str[j]!='\0';)
            {
                if(str[j]>='0'&&str[j]<='9')
                {
                    int tmp = str[j]-'0';
                    j++;
                    while(str[j]>='0'&&str[j]<='9')
                    {
                        tmp = tmp*10 + str[j]-'0';
                        j++;
                    }
                    if(tmp>=100)
                    {
                        sum += tmp;
                    }
                    else
                    {
                        if(num[S0][tmp-1]<2)
                            S0 += my_pow(tmp-1);
                    }
                }
                else j++;
            }
        }
        d[S0] = sum;
        //printf("S0 = %d,sum = %d\n",S0,sum);
        for(int i = 1;i<=n;i++)
        {
            emp[i].s = 0;
            gets(str);
            for(int j = 0;str[j]!='\0';)
            {
                if(str[j]>='0'&&str[j]<='9')
                {
                    int tmp = str[j]-'0';
                    j++;
                    while(str[j]>='0'&&str[j]<='9')
                    {
                        tmp = tmp*10 + str[j]-'0';
                        j++;
                    }
                    if(tmp>=100)
                    {
                        emp[i].c = tmp;
                    }
                    else
                    {
                        emp[i].s += my_pow(tmp-1);
                    }
                }
                else j++;
            }
        }

        for(int i = 0;i=0;j--)
            {
                int to = bin(j,emp[i+1].s,s);
                d[to] = min(d[to],d[j]+emp[i+1].c);
                //printf("i+1 =%d,d[%d] = %d\n",i+1,to,d[to]);
            }
        }
        printf("%d\n",d[S]);
    }
    return 0;
}

/*
2 2 2
10000 1
20000 1
30000 1 2
40000 1 2
*/


你可能感兴趣的:(动态规划)