【UVa658】【SPFA】【状态压缩】It's not a Bug,it's a Featurel.

此题源自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)的输出…

如果有什么意见可以在评论提出哟,渣渣在此跪谢啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值