题意:补丁在修正bug时,有时也会引入新的bug。假定有n个bug和m个补丁,每个补丁用两个长度为n的字符串表示,其中字符串的每个位置表示一个bug。第一串表示打补丁之前的状态,(“-”表示该bug必须不存在,“+”表示该bug必须存在,“0”表示无所谓)第二串表示打补丁之后的状态,(“-”表示该bug不存在,“+”表示该bug存在,“0”表示不改变)每个补丁都有一个执行时间,你的任务是用最少的时间把一个所有bug都存在的软件通过打补丁的方式变的没有bug。一个补丁可以打多次。
很棒的一道最短路的题 ,首先是得能看出是最短路。。。要不是在最短路专题里做到它,肯定就想拿状压dp去做了,但会成环,所有并不能用状压dp去做,正确的方法 就想刘汝佳书上说的那样,把状态看出节点,但不预先处理出边,而是在读到点u时,遍历所有的补丁来处理出边。注意处理边是不能太暴力,要跟状压dp里处理状态一样,用2进制的各种运算来处理,才不会T掉。
这里重点解释一下go()里的 补丁处理 输入为当前状态 和补丁序号 每个补丁里面存 a0是补丁要求状态里0(0是有bug)的位置,所有应该是0的地方在2进制的对应位赋成1 这样当前状态和a0取& 就是把这些应该为0的位取出来 ,为0 才满足补丁要求。其他操作同理。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=214748367;
const int M=1000+5;
//挺实用的 复杂度O(Elog((N)) 其实要小很多
priority_queue<pii,vector<pii>,greater<pii> >q;
int n,m,w;
struct DEBUG
{
int a0,a1,b0,b1;
int v;
} bu[105];
int d[5548576];
int now[105]= {0};
int go(int u,int id)
{
if((u&bu[id].a0)!=0)return -1;
if((u&bu[id].a1)!=bu[id].a1)return -1;
u|=bu[id].b1;
u-=u&bu[id].b0;
return u;
}
int Dijkstra(int u)
{
while(!q.empty())q.pop();
for(int i=0; i<=n; i++) d[i]=i==u?0:inf;
q.push({0,u});
while(!q.empty())
{
pii x=q.top();
q.pop();
// if(x.first>d[n])return 0;
if(x.first!=d[x.second])continue;
int u=x.second;
for(int i=0; i<m; i++)
{
int e=go(u,i);
// cout<<u<<" "<<i<<" "<<e<<" "<<endl;
if(e==-1)continue;
if(d[e]>d[u]+bu[i].v)
{
d[e]=d[u]+bu[i].v;
q.push({d[e],e});
}
}
}
}
int pow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res*=a;
a*=a;
b>>=1;
}
return res;
}
char A[105],B[105];
// + = 0 = bug
int main()
{
int cnt=0;
while(~scnaf("%d%d",&w,&m)&&w+m)
{
n=pow(2,w)-1;
for(int i=0; i<m; i++)
{
scanf("%d%s%s",&bu[i].v,A,B);
int& a0=bu[i].a0;
int& a1=bu[i].a1;
int& b0=bu[i].b0;
int& b1=bu[i].b1;
a1=a0=b1=b0=0;
for(int i=0; i<w; i++)
{
a0*=2;
a1*=2;
b0*=2;
b1*=2;
if(A[i]=='+')a0++;
else if(A[i]=='-')a1++;
if(B[i]=='+')b0++;
else if(B[i]=='-') b1++;
}
}
Dijkstra(0);
printf("Product %d\n",++cnt);
if(d[n]==inf)
puts("Bugs cannot be fixed.");
else
printf("Fastest sequence takes %d seconds.\n",d[n]);
puts("");
}
}