【线性规划与网络流24题 12】软件补丁
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 个正整数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
程序运行结束时,将总耗时数输出。如果问题无解,则输出0。
Sample Input
3 3
1 000 00-
1 00- 0-+
2 0-- -++
Sample Output
8
其实这个题不能放到线性规划和网络流的专题里面
应该是放到最短路里面的
看到题目中的n的范围,很明显:状态压缩
用一个int值记录那些错误有
我们需要找到的就是一条从(1<<n)-1到0的最短路径(花费)
暴力枚举所有的情况,用最短路的算法即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=1<<22;
const int maxm=150;
const int INF=0x3f3f3f3f;
int dis[maxn];
bool vis[maxn];
struct node{
int b1,b2,f1,f2;
int cost;
}p[maxm];
int n,m;
void update(char s[],int &x,int &y){
x=y=0;
for(int i=0;s[i];i++)
if (s[i]=='+')
x|=1<<i;
else if (s[i]=='-')
y|=1<<i;
return;
}
void spfa(int s){
queue<int> q;
memset(vis,false,sizeof(vis));
for(int i=0;i<(1<<n);i++) dis[i]=INF;
dis[s]=0;
q.push(s);
int x,y;
while(!q.empty()){
x=q.front();
q.pop();
vis[x]=false;
for(int i=0;i<m;i++){
if ((x|p[i].b1)==x&&(x&p[i].b2)==0){
y=x&(~p[i].f1);
y|=p[i].f2;
if (dis[y]>dis[x]+p[i].cost){
dis[y]=dis[x]+p[i].cost;
if (!vis[y]){
vis[y]=true;
q.push(y);
}
}
}
}
}
}
int main(){
//freopen("input.txt","r",stdin);
char a[maxm],b[maxm];
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<m;i++){
scanf("%d %s %s",&p[i].cost,a,b);
update(a,p[i].b1,p[i].b2);
update(b,p[i].f2,p[i].f1);
}
spfa((1<<n)-1);
if (dis[0]==INF) puts("0");
else printf("%d\n",dis[0]);
}
return 0;
}