此题源自UVa658,嗯还可以从这里看到->刘汝佳出的紫书P365例题11-6。
链接:戳我戳我qwq
此题,首先如果直接dfs明显会超,boom!
我认为比较巧妙的地方在于:
1.用二进制来表示状态:bug的存在√
2.将’+’单独分类,’0’、’+’再合并分类,分别通过or(|)、 and(&)操作来完成,详细的地方看看代码,有批注哒。特别是对于’-‘的转化处理,可棒了!
3.在这题可以使用dijkstra和SPFA,而我选择了SPFA,相比这两个,虽然后者不如前者稳定,但我仍然认为SPFA只会更优,尤其是状态较多的时候。当然这个也要大家自己感觉吧,很可能我的判断是错的qwq
代码代码!:
#include<iostream>//UVa658 紫P365
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#define LL long long
using namespace std;
const int N=21,M=105,INF=1e9;
int pre[M][2],now[M][2],tot;
LL d[1<<N],t[M];
char b1[N],b2[N];
bool sym[1<<N];//!!!!
void bfs(int n,int m) //SPFA
{
queue<int>q;
for(int i=0;i<(1<<n);i++)
d[i]=INF;
int ww=(1<<n)-1;
d[ww]=0;
q.push(ww);sym[ww]=true;
while(!q.empty())
{
int k=q.front();q.pop();
sym[k]=false;
for(int i=1;i<=m;i++)
if((k|pre[i][0])==k&&(k&pre[i][1])==k)//!!
{
int v=k;
v|=now[i][0];//after存在的必存在
v&=now[i][1];//去掉不存在的
if(d[v]>d[k]+t[i])
{
d[v]=d[k]+t[i];
if(!sym[v])q.push(v);
}
}
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int n=0,m=0;
while(scanf("%d%d",&n,&m)==2&&(n||m))
{
tot++;
printf("Product %d\n",tot);
for(int i=1;i<=m;i++)
{
scanf("%d%s%s",&t[i],&b1,&b2);
pre[i][0]=pre[i][1]=now[i][1]=now[i][0]=0;
for(int j=0;j<n;j++)
{
if(b1[j]=='+')pre[i][0]|=1<<j; //必须存在
if(b1[j]!='-')pre[i][1]|=1<<j; //存在+随意
if(b2[j]=='+')now[i][0]|=1<<j;
if(b2[j]!='-')now[i][1]|=1<<j;
}
}
bfs(n,m);
if(d[0]<INF)printf("Fastest sequence takes %lld seconds.\n",d[0]);
else printf("Bugs cannot be fixed.\n");
printf("\n");
}
return 0;
}
吐槽:
之前测试的时候一个数组开小了就一直Wrong嘤嘤TAT,改了好一会来着,其实我觉得这道题比较有价值所以写一写23333。
最有趣的是这个神(ri)奇(gou)的输出…
如果有什么意见可以在评论提出哟,渣渣在此跪谢啦~