洛谷 P2761 軟件補丁問題
阿新 • • 發佈:2018-08-31
mes include 特定 continue 時間 pan its ont 發放
題目描述
T 公司發現其研制的一個軟件中有 n 個錯誤,隨即為該軟件發放了一批共 m 個補丁程序。每一個補丁程序都有其特定的適用環境,某個補丁只有在軟件中包含某些錯誤而同時又不包含另一些錯誤時才可以使用。一個補丁在排除某些錯誤的同時,往往會加入另一些錯誤。
換句話說,對於每一個補丁 i,都有 2 個與之相應的錯誤集合 B1[i]和 B2[i],使得僅當軟件包含 B1[i]中的所有錯誤,而不包含 B2[i]中的任何錯誤時,才可以使用補丁 i。補丁 i 將修復軟件中的某些錯誤 F1[i],而同時加入另一些錯誤 F2[i]。另外,每個補丁都耗費一定的時間。
試設計一個算法,利用 T 公司提供的 m 個補丁程序將原軟件修復成一個沒有錯誤的軟件,並使修復後的軟件耗時最少。對於給定的 n 個錯誤和 m 個補丁程序,找到總耗時最少的軟件修復方案。
1<=n<=20, 1<=m<=100
問題分析:
由於n的範圍很小,我們可以把每一個漏洞的狀態用0和1來表示,即將當前系統狀態用一個01的串來表示,狀態壓縮。
DP即可,但是由於DP狀態會有1e6種,每種轉移要m次,復雜度太大了。。。所以用最短路解決問題,可以減少一些不會到達的狀態。
起點為所有漏洞都未被修復的狀態(11.....11),終點為所有漏洞都已被修復的狀態(00....00).
代碼:
#include <bits/stdc++.h> using namespace std; char s[25]; int t[105]; int sta1[105],sta2[105]; int res1[105],res2[105]; int dis[2100000],vis[2100000]; queue<int> Q; int main() { memset(dis,0x3f,sizeof(dis)); int n,m; scanf("%d%d",&n,&m); for(int i = 1;i <= m;++i){ scanf("%d",&t[i]); scanf("%s",s); for(int j = 0;j < n;++j){ if(s[j] == ‘+‘) sta1[i] += (1<<j); else if(s[j] == ‘-‘) sta2[i] += (1<<j); } scanf("%s",s); for(int j = 0;j < n;++j){ if(s[j] == ‘+‘) res2[i] += (1<<j); else if(s[j] == ‘-‘) res1[i] += (1<<j); } } int now = (1<<n)-1; dis[now] = 0; Q.push(now); vis[now] = 1; while(!Q.empty()){ now = Q.front(); Q.pop(); for(int i = 1;i <= m;++i){ if((now & sta1[i]) != sta1[i]) continue; if((~now & sta2[i]) != sta2[i]) continue; int tmp = (now & (~res1[i])) | res2[i]; if(dis[tmp] > dis[now] + t[i]){ dis[tmp] = dis[now] + t[i]; if(!vis[tmp]) vis[tmp] = 1,Q.push(tmp); } } vis[now] = 0; } if(dis[0] == 0x3f3f3f3f) puts("0"); else printf("%d\n",dis[0]); return 0; }
洛谷 P2761 軟件補丁問題