1. 程式人生 > 其它 >網路流24題(十二)

網路流24題(十二)

網路流24題(十二)

十二、軟體補丁問題

題目描述

T 公司發現其研製的一個軟體中有 n 個錯誤,隨即為該軟體發放了一批共 m 個補丁程式。每一個補丁程式都有其特定的適用環境,某個補丁只有在軟體中包含某些錯誤而同時又不包含另一些錯誤時才可以使用。一個補丁在排除某些錯誤的同時,往往會加入另一些錯誤。

換句話說,對於每一個補丁 i,都有 2 個與之相應的錯誤集合 B1[i]和 B2[i],使得僅當軟體包含 B1[i]中的所有錯誤,而不包含 B2[i]中的任何錯誤時,才可以使用補丁 i。補丁 i 將修復軟體中的某些錯誤 F1[i],而同時加入另一些錯誤 F2[i]。另外,每個補丁都耗費一定的時間。

試設計一個演算法,利用 T 公司提供的 m 個補丁程式將原軟體修復成一個沒有錯誤的軟體,並使修復後的軟體耗時最少。對於給定的 n 個錯誤和 m 個補丁程式,找到總耗時最少的軟體修復方案。

輸入格式

第 1 行有 2 個正整數 n 和 m,n 表示錯誤總數,m表示補丁總數,1<=n<=20, 1<=m<=100。

接下來 m 行給出了 m 個補丁的資訊。每行包括一個正整數,表示執行補丁程式 i 所需時間,以及 2 個長度為 n 的字串,中間用一個空格符隔開。

第 1 個字串中,如果第 k 個字元 bk 為“+”,則表示第 k 個錯誤屬於 B1[i],若為“-”,則表示第 k 個錯誤屬於 B2[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 而改變。

輸出格式

程式執行結束時,將總耗時數輸出。如果問題無解,則輸出 0。

題解

模型:

狀壓最短路

建圖與實現:

對於每一個錯誤都有被修復和修復兩種情況,考慮二進位制狀壓。每一位都錯就是初始狀態全1,目標狀態全0。
考慮狀態的轉移(其實就是一個字串處理),對於每一種給出的補丁可以理解為從一種狀態轉移到另外一種狀態。(注意是一種,不是一個,所以需要列舉補丁)

然後跑最短路就行了。

程式碼

#include <iostream>
#include <queue>
#include <cstring>
#include <map>
#include <stack>
#define ll long long

const ll N = (1<<20)+50,M = 150;
const ll inf = 0x3f3f3f3f;
using namespace std;
struct Edge{
    ll w;
    string b,f;
}edge[M];
struct node{
    ll id,dis;
    bool operator < (const node &x)const{
        return dis > x.dis;
    }
};
ll n,m,s,t;
ll mov(ll x,Edge eg){
    for(ll tmp = x,cnt = 0;cnt<n;cnt++,tmp>>=1){
        ll pos = n-cnt-1;
        if(eg.b[pos] == '0' || (eg.b[pos] == '-' && (tmp&1) == 0) || (eg.b[pos] == '+' && (tmp&1) == 1)){
            if(eg.f[pos] == '0')continue;
            if(eg.f[pos] == '+')x = x|(1<<cnt);
            if(eg.f[pos] == '-')x = x&~(1<<cnt);
        }
        else return -1;
    }
    return x;
}
priority_queue<node> q;
bool done[N];
ll d[N];
void dij(){
    for(ll i = 0;i <= s;i++){
        d[i] = (i==s)?0:inf;
        done[i] = false;
    }
    //done[s] = true;
    q.push({s,d[s]});
    while(!q.empty()){
        node x = q.top();q.pop();
        //cout<<x.id<<' '<<x.dis<<endl;
        if(done[x.id]) continue;
        done[x.id] = true;
        for(ll i = 1;i <= m;i++){
            ll v = mov(x.id,edge[i]);
            //cout<<x.id<<' '<<i<<' '<<v<<endl;
            if(v == -1||done[v])continue;
            if(d[v] > x.dis+edge[i].w){
                d[v] = x.dis+edge[i].w;
                q.push({v,d[v]});
            }
        }
    }
    d[t] = d[t] == inf?0:d[t];
    cout<<d[t]<<endl;
}
int main() {
    cin>>n>>m;
    for(ll i = 1;i <= m;i++){
        cin>>edge[i].w>>edge[i].b>>edge[i].f;
    }
    s = (1<<n)-1,t = 0;
    dij();
    return 0;
}