1. 程式人生 > >UVA-10817- Headmaster's Headache(狀壓DP)

UVA-10817- Headmaster's Headache(狀壓DP)

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;
}