USACO 5.3.1 Milk Measuring 量取牛奶 milk4

這道題要用到迭代加深搜索(DFSID)。由於要求輸出的是使用最少的牛奶桶,所以要先找牛奶桶數量爲1的時候所有的組合,如果沒有解再找牛奶桶數量爲2...直到牛奶桶數量爲P。

當搜索到一個組合,判斷用這些牛奶桶是否能組成目標解的時候,可以用動態規劃的方法來做。設f[i]是當需求的牛奶爲i時,能否形成這個組合,是一個布爾型數組。 初始條件 f[0]=true 狀態轉移方程 f[i]=f[i] or f[ i-v[j] ] (j爲使用的所有牛奶桶) 目標狀態 f[Q] 如果f[Q]爲true,則當前解合法,直接輸出即可。

但是如果僅僅這樣寫還是有一組數據過不去,需要進行一些優化。要優化動態規劃的過程。 注意一個重要的信息,找到的組合中,每個牛奶桶至少用了一次。上面的狀態轉移方程中有許多某個牛奶桶使用0次的冗餘狀態。可以在初始的時候對(i=1..Q/v[第一個桶]) f[ i*v[第一個桶] ]賦值爲true。對每個其他的桶的狀態可以直接由前面的狀態得出。

經過這個優化,數據就可以全過了。

<pre><span>USER: CmYkRgB123 CmYkRgB123 [cmykrgb1]
TASK: milk4
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 2864 KB]
   Test 2: TEST OK [0.011 secs, 2860 KB]
   Test 3: TEST OK [0.000 secs, 2864 KB]
   Test 4: TEST OK [0.000 secs, 2864 KB]
   Test 5: TEST OK [0.000 secs, 2864 KB]
   Test 6: TEST OK [0.000 secs, 2860 KB]
   Test 7: TEST OK [0.130 secs, 2860 KB]
   Test 8: TEST OK [0.032 secs, 2864 KB]
   Test 9: TEST OK [0.022 secs, 2860 KB]
   Test 10: TEST OK [0.194 secs, 2860 KB]

All tests OK.
</span>
<span>Your program ('milk4') produced all correct answers!  This is your
submission #3 for this problem.  <strong>Congratulations!</strong>
</span>
</pre>
/*
ID: cmykrgb1
PROG: milk4
LANG: C++
*/

#include <iostream>
#include <fstream>
#define MAXP 101
#define MAXQ 20001

using namespace std;

ifstream fi("milk4.in");
ofstream fo("milk4.out");

int Q,P,ans,v[MAXP],use[MAXP];

inline int cmp(const void * a,const void * b)
{
    return *(int *)a<*(int *)b?-1:1;
}

void init()
{
    int i;
    fi >> Q >> P;
    for (i=1;i<=P;i++) fi >> v[i];
    qsort(v+1,P,sizeof(v[0]),cmp);
}

void print()
{
    fo << ans;
    for (int i=1;i<=ans;i++) 
        fo << ' ' << v[ use[i] ];
    fo << endl;
    fi.close();    
    fo.close();    
    exit(0);
}

void judge()
{
    int i,j;
    bool f[MAXQ];
    memset(f,0,sizeof(f));
    for (i=1;i<=Q/v[use[1]];i++)
        f[ i*v[use[1]] ]=true;
    for (i=2;i<=ans;i++)
        for (j=v[use[i]];j<=Q;j++) //第一種牛奶桶至少用了一次
            f[j] |= f[ j- v[use[i]] ] ;
    if (f[Q]) 
        print();
}

void dfs(int k)
{
    int i,j;
    for (i=use[k-1]+1;i<=P-ans+k;i++)
    {
        use[k]=i;
        if (k==ans)    
            judge();
        else 
            dfs(k+1);
    }
}

void DFSID()
{
    for (ans=1;ans<=P;ans++)
        dfs(1);
}

int main()
{
    init();
    DFSID();
    return 0;
}

相關日誌