网络流二十四题之十二 —— 软件补丁问题(BUG)

来源:互联网 发布:淘宝小店推广 编辑:程序博客网 时间:2024/05/21 12:44

附一个有良心的可以测二十四题的评测网站(戳我戳我)


软件补丁问题


Description

T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。
每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。
一个补丁在排除某些错误的同时,往往会加入另一些错误。
换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]B2[i],使得仅当软件包含 B1[i] 中的所有错误,而不包含 B2[i] 中的任何错误时,才可以使用补丁 i
补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]
另外,每个补丁都耗费一定的时间。
试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。

对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。


Input

1 行有 2 个正整数 nmn 表示错误总数,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 为“-”1 ,则表示第 k 个错误属于 F1[i],若为“+”,则表示第 k 个错误属于 F2[i],若为“0” ,则第 k 个错误既不属于 F1[i] 也不属于 F2[i],即软件中是否包含第 k 个错误不会因使用补丁 i 而改变。


Output

将总耗时数输出。如果问题无解,则输出 0


Sample Input

3 3
1 000 00-
1 00- 0-+
2 0– -++


Sample Output

8


Solution

一看到这道题目我就惊呆了——这跟网络流能扯到一块儿??

因为 n<=20,我第一反应状压DP,而可能出现的环打消了我的念想。

但是很快就愉快地发现,本题就是一个水水的最短路……
我之前的想法其实也没有错,状态压缩,求最短路即可。


Code

代码很丑,不要介意……

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <queue>  
  5.   
  6. #define INF 0x3f3f3f3f   
  7.   
  8. using namespace std;  
  9.   
  10. int cnt;  
  11.   
  12. queue<int>q;  
  13. bool in_stack[1100010];  
  14. int dis[1100010];  
  15.   
  16. int head[1100010];  
  17. int nxt[1100010];  
  18. int data[1100010];  
  19. int wei[1100010];  
  20. int n,m;  
  21. int tt[5000];  
  22. char s1[5000],s2[5000];  
  23. bool b1[200][200];  
  24. bool b2[200][200];  
  25. bool f1[200][200];  
  26. bool f2[200][200];  
  27. bool vis[1100010][101];  
  28. int zz[100];  
  29.   
  30. void add(int x,int y,int z){  
  31.     nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=z;head[x]=cnt++;  
  32. }  
  33.   
  34. int Can(int tot,int now){  
  35.     int tmp=0;  
  36.     zz[0]=0;  
  37.     for(int i=1;i<=n;i++)zz[i]=0;  
  38.     while(now){  
  39.         zz[++zz[0]]=now%2;  
  40.         now/=2;   
  41.     }  
  42.     for(int i=n;i>=1;i–){  
  43.         if((zz[i]==0&&b1[tot][n-i+1]))return -1;  
  44.         if(zz[i]==1&&b2[tot][n-i+1])return -1;  
  45.     }  
  46.     for(int i=n;i>=1;i–){  
  47.         if(f1[tot][n-i+1])zz[i]=0;  
  48.         if(f2[tot][n-i+1])zz[i]=1;  
  49.         tmp+=(1<<(i-1))*zz[i];  
  50.     }  
  51.     return tmp;  
  52. }  
  53.   
  54. void dfs(int now){  
  55.     if(now==0)return;  
  56.     for(int i=1;i<=m;i++){   
  57.         int tmp=Can(i,now);  
  58.         if(tmp==-1)continue;  
  59.         if(vis[tmp][i])add(now,tmp,tt[i]);  
  60.         else{  
  61.             add(now,tmp,tt[i]);  
  62.             vis[tmp][i]=true;  
  63.             dfs(tmp);   
  64.         }  
  65.     }  
  66. }  
  67.   
  68. void spfa(){  
  69.     memset(dis,0x3f,sizeof dis);  
  70.     q.push((1<<n)-1);  
  71.     dis[(1<<n)-1]=0;  
  72.     in_stack[(1<<n)-1]=true;  
  73.     while(!q.empty()){  
  74.         int now=q.front();  
  75.         q.pop();  
  76.         in_stack[now]=false;  
  77.         for(int i=head[now];i!=-1;i=nxt[i]){  
  78.             if(dis[data[i]]>dis[now]+wei[i]){  
  79.                 dis[data[i]]=dis[now]+wei[i];  
  80.                 if(!in_stack[data[i]]){  
  81.                     q.push(data[i]);  
  82.                     in_stack[data[i]]=true;   
  83.                 }  
  84.             }  
  85.         }  
  86.     }  
  87.     if(dis[0]==INF)printf(“0\n”);  
  88.     else printf(“%d\n”,dis[0]);  
  89. }  
  90.   
  91. int main(){  
  92.       
  93.     memset(head,-1,sizeof head);  
  94.     scanf(”%d%d”,&n,&m);  
  95.     for(int i=1;i<=m;i++){  
  96.         scanf(”%d%s%s”,&tt[i],s1,s2);  
  97.         for(int j=0;j<n;j++){   
  98.             if(s1[j]==‘0’)continue;   
  99.             if(s1[j]==‘+’)b1[i][j+1]=true;  
  100.             if(s1[j]==‘-‘)b2[i][j+1]=true;  
  101.         }  
  102.         for(int j=0;j<n;j++){   
  103.             if(s2[j]==‘0’)continue;   
  104.             if(s2[j]==‘-‘)f1[i][j+1]=true;  
  105.             if(s2[j]==‘+’)f2[i][j+1]=true;  
  106.         }  
  107.     }  
  108.     dfs((1<<n)-1);  
  109.     spfa();  
  110.     return 0;   
  111. }  

  1. 原题中,此处及下一个 ‘+’ 处弄混了,已予以修正。 ↩
1 0