題目描述
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 個錯誤屬於 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 而改變。
程序運行結束時,將總耗時數輸出。如果問題無解,則輸出 0。
思路:說是網絡流,但是大家好像都是用位壓縮+最短路,強行用費用流的話也沒什麼意義,錯誤最多二十處,可以用二十位二進制代表每一種狀態。根據題意,僅當軟件包含 B1[i]中的所有錯誤,而不包含 B2[i]中的任何錯誤時,纔可以使用補丁 i。補丁 i 將修復軟件中的某些錯誤 F1[i],而同時加入另一些錯誤 F2[i]。把每個補丁的b1,b2,f1,f2處理出來,在鬆弛造作時按照題意進行轉移,答案就是全1狀態跑到全0狀態的最短路。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1<<21;
const int INF=1e9;
struct Patch{
int b1,b2,f2,f1,t;
Patch() {
b1=b2=f1=f2=t=0;
}
}p[120];
int n,m,dis[maxn];
bool inq[maxn];
int spfa() {
memset(inq,0,sizeof(inq));
for(int i=0;i<=(1<<n);i++) dis[i]=INF;
int u=(1<<n)-1;
dis[u]=0;
queue<int> Q;
inq[u]=true;
Q.push(u);
while(!Q.empty()) {
u=Q.front();
Q.pop();
inq[u]=false;
for(int i=1;i<=m;i++) {
if((p[i].b1 & u)==p[i].b1 && (p[i].b2&u)==0 ) {
int v=u&(~p[i].f1)|p[i].f2;
if(v==u) continue;
if(dis[v] > dis[u]+p[i].t) {
dis[v]=dis[u]+p[i].t;
if(!inq[v]) {
Q.push(v);
inq[v]=true;
}
}
}
}
}
return dis[0];
}
int main() {
while(scanf("%d%d",&n,&m) != EOF) {
string s;
for(int i=1;i<=m;i++) {
int k=1;
scanf("%d",&p[i].t);
cin>>s;
int l=s.length();
for(int j=0;j<l;j++) {
if(s[j]=='+') {
p[i].b1^=k;
}
else if(s[j]=='-') {
p[i].b2^=k;
}
k=k<<1;
}
cin>>s;
k=1;
l=s.length();
for(int j=0;j<l;j++) {
if(s[j]=='+') {
p[i].f2^=k;
}
else if(s[j]=='-') {
p[i].f1^=k;
}
k=k<<1;
}
}
int ans=spfa();
if(ans==INF) {
puts("0");
}
else {
printf("%d\n",ans);
}
}
}