nefu489軟件補丁問題

«問題描述:
T 公司發現其研製的一個軟件中有n 個錯誤,隨即爲該軟件發放了一批共m 個補丁程序。每一個補丁程序都有其特定的適用環境,某個補丁只有在軟件中包含某些錯誤而同時又
不包含另一些錯誤時纔可以使用。一個補丁在排除某些錯誤的同時,往往會加入另一些錯誤。換句話說,對於每一個補丁i,都有2 個與之相應的錯誤集合B1[i]和B2[i],使得僅當軟件包含B1[i]中的所有錯誤,而不包含B2[i]中的任何錯誤時,纔可以使用補丁i。補丁i 將修復軟件中的某些錯誤F1[i],而同時加入另一些錯誤F2[i]。另外,每個補丁都耗費一定的時間。試設計一個算法,利用T 公司提供的m個補丁程序將原軟件修復成一個沒有錯誤的軟件,並使修復後的軟件耗時最少。
«編程任務:
對於給定的n個錯誤和m個補丁程序,找到總耗時最少的軟件修復方案。
«數據輸入:
由文件input.txt 提供輸入數據。文件第1 行有2 個正整數n 和m,n 表示錯誤總數,m表示補丁總數,1<=n<=20, 1<=m<=100。接下來m行給出了m個補丁的信息。每行包括一
個正整數,表示運行補丁程序i 所需時間,以及2 個長度爲n的字符串,中間用一個空格符隔開。第1 個字符串中,如果第k個字符bk爲“+”,則表示第k個錯誤屬於B1[i],若爲“-”,
則表示第k個錯誤屬於B21[i],若爲“0”,則第k個錯誤既不屬於B1[i]也不屬於B2[i],即軟件中是否包含第k個錯誤並不影響補丁i的可用性。第2 個字符串中,如果第k個字符bk
爲“+”,則表示第k個錯誤屬於F1[i],若爲“-”,則表示第k個錯誤屬於F2[i],若爲“0”,則第k個錯誤既不屬於F1[i]也不屬於F2[i],即軟件中是否包含第k個錯誤不會因使用補丁i 而改變。
«結果輸出:
程序運行結束時,將總耗時數輸出到文件output.txt中。如果問題無解,則輸出0。
輸入文件示例 輸出文件示例

3 3 8
1 000 00-
1 00- 0-+

2 0--  -++

【問題分析】
求一個狀態到另一個狀態變換的最少費用,最短路徑問題。
【建模方法】
軟件的狀態用二進制位表示,第i位爲第i個錯誤是否存在。把每個狀態看做一個頂點,一個狀態應用一個補丁到達另一狀態,連接一條權值爲補丁時間的有向邊。求從初始狀態到目標狀態的最短路徑即可。

#include<cstdio>
using namespace std;
const int mm=111;
const int mn=1<<22;
int i,j,k,n,m,cost[mm],a1[mm],a2[mm],b1[mm],b2[mm],f[mn];
char s1[22],s2[22];
void dfs(int now)
{
    if(f[now]>=f[0])return;
    for(int i=1,tmp;i<=m;++i)
    if((now&a1[i])==a2[i])
    {
        tmp=(now&b1[i])|b2[i];
        if(f[now]+cost[i]<f[tmp])f[tmp]=f[now]+cost[i],dfs(tmp);
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=-1)
    {
        for(i=0;i<mn;++i)f[i]=mn;
        for(i=1;i<=m;++i)
        {
            scanf("%d%s%s",&cost[i],s1,s2);
            a1[i]=a2[i]=b1[i]=b2[i]=0;
            for(j=0;j<n;++j)
            {
                a1[i]<<=1,a2[i]<<=1,b1[i]<<=1,b2[i]<<=1;
                if(s1[j]!='0')++a1[i];
                if(s1[j]=='+')++a2[i];
                if(s2[j]!='-')++b1[i];
                if(s2[j]=='+')++b2[i];
            }
        }
        f[(1<<n)-1]=0;
        dfs((1<<n)-1);
        printf("%d\n",f[0]<mn?f[0]:0);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章