程序补丁(bugs)
时间限制: 1000 ms 内存限制: 65536 KB【题目描述】
一个程序总有个错误,公司经常发布补丁来修正这些错误,遗憾的是,每用一个补丁,在修正某些错误的时候,同时会加入某些错误,每个补丁都有一定运行时间。
某公司发表了一个游戏,出现了n个错误B={b1,b2,b3,……bn},于是该公司发布了m个补丁,每个补丁的应用都是有条件的(即哪些错误必须存在,哪些错误不能存在)。
求最少需要多少时间可全部修正这些错误。
【输入】
输入文件第一行有两个正整数n和m,n表示错误总数,m表示补丁总数,1≤n≤20,1≤m≤100。接下来m行给出了m个补丁的信息。每行包括一个正整数(表示此补丁程序的运行时间)和两个字符串,
第一个字符串描述了应用该补丁的条件。字符串的第i个字符,如果是‘+’,表示在软件中必须存在第bi号错误;如果是‘-’,表示软件中错误bi不能存在;如果是‘0’,则表示错误bi存在或不存在均可(即对应用该补丁没用影响)。
第二个字符串描述了应用该补丁的效果。字符串的第i个,如果是‘+’,表示产生了一个新错误bi;如果是‘-’,表示错误bi被修改好了;如果是‘0’,则表示错误bi不变(即原来存在的,仍然存在;原来不存在,还是不存在)。
【输出】
输出一个整数,如果问题有解,输出总耗时。否则输出-1。
【输入样例】
3 5 1 0-+ -+- 3 +-- -00 4 000 00- 6 +0+ -0- 3 0+0 0-0
【输出样例】
7
【思路分析】
这道题首先就会想到是状态压缩,但由于是求最短用时所以我们不用动规,改写spfa。
首先将每种状态记录在一个节点中,每次扩展更新从起点到每个节点的最短路(只要可以从一个状态到另一个状态就可以更新)
这道题其实非常考验位运算,是一道练习位运算的很好的题,具体位运算的精髓还是在代码里去领悟吧!!!
【代码实现】
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 queue<int> que; 7 const int MAXN=(1<<20)+7; 8 int b1[105],b2[105],f1[105],f2[105],t1[105],n,m; 9 int dis[MAXN]; 10 bool vis[MAXN]; 11 void spfa() 12 { 13 memset(vis,false,sizeof(vis)); 14 memset(dis,0x3f3f3f3f,sizeof(dis)); 15 int s=(1<<n);s--; 16 que.push(s); 17 vis[s]=true; 18 dis[s]=0; 19 while(!que.empty()) 20 { 21 int now=que.front(); 22 que.pop(); 23 vis[now]=false; 24 for(int i=1;i<=m;i++) 25 { 26 if(((b1[i]&now)==b1[i])&&((b2[i]&now)==0)) 27 { 28 int son; 29 son=(now|f2[i]); 30 son=(son&(~f1[i])); 31 if(dis[son]>dis[now]+t1[i]) 32 { 33 dis[son]=dis[now]+t1[i]; 34 if(!vis[son]) 35 { 36 que.push(son); 37 vis[son]=true; 38 } 39 } 40 } 41 } 42 } 43 } 44 int main() 45 { 46 scanf("%d%d",&n,&m); 47 for(int i=1;i<=m;i++) 48 { 49 char bb[20],ff[20]; 50 int tt; 51 cin>>tt; 52 cin>>bb>>ff; 53 t1[i]=tt; 54 for(int j=0;j<n;j++) 55 { 56 if(bb[j]=='+') b1[i]=b1[i]|(1<<j); 57 if(bb[j]=='-') b2[i]=b2[i]|(1<<j); 58 if(ff[j]=='-') f1[i]=f1[i]|(1<<j); 59 if(ff[j]=='+') f2[i]=f2[i]|(1<<j); 60 } 61 } 62 spfa(); 63 if(dis[0]==0x3f3f3f3f) printf("-1"); 64 else printf("%d",dis[0]); 65 return 0; 66 }