软件补丁问题(SPFA+位运算)

洛谷P2761 1.考虑到所有的错误只有“修复,未修复”两种情况,所以可以用0,1标记压缩状态,采用位运算减少时空浪费。 又考虑到有修复时间的关系,将时间抽象成边,将状态抽象为点(设修复为0,未修复为1)最后从(1<<n)-1开始寻找到0的最短路,SPFA一边建图一边松弛即可。

2.实现过程中,难点在于对二进制表示,以及位运算组合判断的处理。 首先,状态要表示(见前); 其次,补丁b,f要表示。 最初考虑用两个数来表示b,f,发现受“不动错误”影响,无法转移运算。故采用四个数记录,b+,b-,f+,f-。再推倒出位运算判断方式,以及转移方式即可。

最终位运算方式: 判断:b+:(原状态~)&bp为0可以通过 b-:&为0可以通过 转移(更新)f+:| f-:(fj取反)&原状态

另:b+b-f+f-定义比较繁琐,利用草稿纸码上条件思路比较省事。

附代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int hd=1,tl=0;
int q[1050000];
bool vis[1050000];
int dis[1050000];
struct repair{
    int t;
    int bp,bj,fp,fj;
}bu[111];
int main()
{
    char kk[23];
    char h;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d ",&bu[i].t);
        for(int j=1;j<=n;j++)
        {
            h=getchar();
            if(h==‘+‘) bu[i].bp+=1<<(n-j);
            if(h==‘-‘) bu[i].bj+=1<<(n-j);
        }
        h=getchar();
        for(int j=1;j<=n;j++)
        {
            h=getchar();
            if(h==‘+‘) bu[i].fp+=1<<(n-j);
            if(h==‘-‘) bu[i].fj+=1<<(n-j);
        }
    }
    //for(int i=1;i<=m;i++)
     //cout<<bu[i].t<<" "<<bu[i].bp<<" "<<bu[i].bj<<" "<<bu[i].fp<<" "<<bu[i].fj<<endl;
    //cout<<endl;
    q[++tl]=(1<<n)-1;
    memset(dis,0x3f3f3f3f,sizeof dis);
    dis[(1<<n)-1]=0;
    while(hd<=tl)
    {
        int zhuang=q[hd];hd++;vis[zhuang]=0;
        //cout<<zhuang<<" "<<dis[zhuang]<<endl;
        for(int i=1;i<=m;i++)
        {
            if(((~zhuang)&bu[i].bp)!=0) continue;
            if((zhuang&bu[i].bj)!=0) continue;
            //cout<<"panduan "<<i<<" && "<<zhuang<<" == "<<(zhuang&bu[i].bj)<<endl;
            int tt=(zhuang|bu[i].fp);
            tt=(tt&(~bu[i].fj));
            if(dis[tt]>dis[zhuang]+bu[i].t)
            {

                dis[tt]=dis[zhuang]+bu[i].t;
                //cout<<"gengxin  "<<i<<" -> "<<tt<<" "<<dis[tt]<<endl;
                if(!vis[tt])
                {
                    vis[tt]=1;
                    q[++tl]=tt;
                }
            }
        }
    }
    if(dis[0]==0x3f3f3f3f) printf("0");
    else printf("%d",dis[0]);
    return 0;
}

总结:位运算一定要自己手动考虑,谁都可以看懂,但是有时候不容易想。

注意位运算优先级。

原文地址:https://www.cnblogs.com/Miracevin/p/9031461.html

时间: 2024-10-07 22:24:24

软件补丁问题(SPFA+位运算)的相关文章

It&amp;#39;s not a Bug, It&amp;#39;s a Feature! (poj 1482 最短路SPFA+隐式图+位运算)

Language: Default It's not a Bug, It's a Feature! Time Limit: 5000MS   Memory Limit: 30000K Total Submissions: 1353   Accepted: 516 Description It is a curious fact that consumers buying a new software product generally do not expect the software to

洛谷 P2761 软件补丁问题 【spfa】

-为什么最短路的题会出现在网络流24里?? 因为范围是15所以直接把每个状态作为一个点,向它能转移到的点连有向边即可.可以不用建图(据说建图存不下?),直接枚举m个转移方案.位运算比较麻烦注意不要写错. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1500005,inf=1e9; int n,m,d

P2761 软件补丁问题

P2761 软件补丁问题 思路 貌似不用网络流,直接状态压缩 用spfa跑最短路,直接判断是否能过 位运算太渣了,WA了好几发 代码 #include <bits/stdc++.h> using namespace std; const int N = 21, M = 101, inf = 0x3f3f3f3f; int read() { int x = 0, f = 1; char s = getchar(); for(; s > '9' || s < '0'; s = getc

【网络流24题】软件补丁问题(最短路)

[网络流24题]软件补丁问题(最短路) 题面 COGS 题解 这题貌似和网络流没啥关系 因为错误很少 可以直接状压 然后利用位运算直接跑最短路就行了 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map&

Objective-C使用位运算设计可复选的枚举

使用位运算设计可复选的枚举 一.枚举使用的一个小例子 在软件开发中,枚举是我们会经常会用到的一种编程方式,通过枚举,可以使我们的代码更具可读性与统一性.通常情况下,我们会通过typedef来定义一种枚举的类型来使用.例如: typedef enum {     para1,     para2,     para3 }myEnum; 我们可以在函数的参数中来使用它: -(void)testEunm:(myEnum)para{     switch (para) {         case pa

【UVA】658 - It&#39;s not a Bug, it&#39;s a Feature!(隐式图 + 位运算)

这题直接隐式图 + 位运算暴力搜出来的,2.5s险过,不是正法,做完这题做的最大收获就是学会了一些位运算的处理方式. 1.将s中二进制第k位变成0的处理方式: s = s & (~(1 << pos)); 将s中二进制第k位变成1的处理方式: s = s | (1 << pos); 2.二进制运算: [1] & : 1 & 1 = 1 , 1 & 0 = 0 , 0 & 0 = 0; 快速判断奇偶性: if(a & 1);//为奇数

[luoguP2761] 软件补丁问题(状压最短路)

传送门 n <= 20 很小 所以可以状态压缩 然后因为可能存在环,所以不能DP 那么就用spfa找最短路 被位运算坑了,不清楚优先级一定要加括号 ——代码 1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #define M 301 6 #define N 4000001 7 8 int n, m; 9 int b1[M], b2[M

基本数据类型-位运算-字符集-流

基本数据类型-位运算-字符集-流 1.基本类型 类型 字节数 范围 byte 1 -128 ~ 127 short 2 -32768 ~32767 int 4 \(- 2^{31}\) ~ $ 2^{31} - 1$ long 8 float 4 double 8 boolean 1 char 2 注意:short.char.byte参与运算时直接抬升到int型. 思考题: 0是整数还是负数? 字节数-128在内存中的存储形态是如何的? 字节范围为何是从-128到127之间,而不是-127到正的

位运算

位运算的实际应用场景 http://blog.csdn.net/zmazon/article/details/8262185