题意: 修补bug,会引入新的bug。n(n<=20)个bug和m(m<=100)个补丁,每个补丁用两个长度为n的字符串表示,每个位置表示一个bug。一串表示打补丁前的状态(“-”表示该bug必须不存在,“+”表示必须存在,“0”表示无所谓),二串表示打补丁后的状态(“-”表示不存在,“+”表示存在,“0”表示不变)。每个补丁有一个时间,用最少的时间变得没有bug。一个补丁可用多次。
要满足一串的状态才能变成二串的状态。
分析:把状态看做结点,状态转移看做边,然后用spfa求解。
不需要把图存好,每次取出一个结点,直接枚举m个补丁,看是否能够打得上。
状态用二进制表示,类似状压dp那样状态压缩。
一串:
+ 存入s[1][i]
+ 和0 存入s[0][i]
二串:
同上,存入t[1][i] 和t[0][i]
u | s[1][i] == u s[1][i]等于1的地方u也等于1 存在的一定要存在
u & s[0][i] == u s[0][i]为0的地方u也必定等于0 不存在的一定要不存在
两个条件合起来满足一串的要求
变成二串状态
v = u;
v |= t[1][i];
v &= t[0][i];
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N= 2000;
const int maxn = 1e3+10;
const int maxm = 2000000001;
const int MOD = 1e6;
int n,m;
int w[110];
int s[2][110],t[2][110];
int dis[1<<25],inq[1<<25];
void spfa(int st)
{
for(int i = 0;i <= st;i++) dis[i]=inf;
memset(inq,0,sizeof(inq));
queue<int> Q;
dis[st] = 0;
inq[st] = 1;
Q.push(st);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i = 0;i < m;i++)
if( ((u | s[1][i]) == u) && ((u & s[0][i]) == u) ) //是否满足一串状态
{
int v = u;
v |= t[1][i];
v &= t[0][i]; //变成二串状态
if(dis[u] + w[i] < dis[v])
{
dis[v]=dis[u]+w[i];
if(!inq[v])
{
Q.push(v);
inq[v]=1;
}
}
}
}
}
char a[25],b[25];
int main(){
#ifdef LOCAL
freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
//freopen("output.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
int kase =0;
while (cin>>n>>m && (n+m))
{
cout<<"Product "<<++kase<<endl;
memset(s,0,sizeof(s));
memset(t,0,sizeof(t));
for(int i = 0;i < m;i++)
{
cin>>w[i]>>a>>b;
for(int j = 0;j < n;j++)
{
if(a[j]=='+') s[1][i]+=(1<<j);
if(a[j]!='-') s[0][i]+=(1<<j);
if(b[j]=='+') t[1][i]+=(1<<j);
if(b[j]!='-') t[0][i]+=(1<<j);
}
}
spfa((1<<n)-1);
if(dis[0] == inf) cout<<"Bugs cannot be fixed.\n";
else cout<<"Fastest sequence takes "<<dis[0]<<" seconds.\n";
cout<<endl;
}
return 0;
}