软件补丁问题–网络流24题
题意:
对于每一个软件,有特定的使用方法,简单来说,就是
软件只有必须有某些漏洞但是有没有某一些漏洞的时候才会有用
在使用补丁的同时,会消去某一些漏洞,但是同时也会引入某些漏洞
一开始有 n 个漏洞
输入的是
n
n
和 ,就是有
m
m
个补丁(每个补丁可以重复使用)
每 行会有
2
2
个字符串:
第 1 个字符串中,如果第 k 个字符 为“+”,则表示第 k 个错误属于
B1[i]
B
1
[
i
]
,若为“-”,则表示第 k 个错误属于
B21[i]
B
21
[
i
]
,若为“0”,则第
k
k
个错误既不属于 也不属于
B2[i]
B
2
[
i
]
,即软件中是否包含第
k
k
个错误并不影响补丁 的可用性。
第 2 个字符串中,如果第 k 个字符 bk b k 为“-”,则表示第 k 个错误属于 F1[i] F 1 [ i ] ,若为“+”,则表示第 k 个错误属于 F2[i] F 2 [ i ] ,若为“0”,则第 k k 个错误既不属于 也不属于 F2[i] F 2 [ i ] ,即软件中是否包含第 k k 个错误不会因使用补丁 而改变。
分析:
其实这道题我不知道为什么
是网络流24题,其实就是状态压缩DP
是
网
络
流
24
题
,
其
实
就
是
状
态
压
缩
D
P
我们用mark表示01分别表示是否还有病毒,而dp[mark]表示最小代价!
我
们
用
m
a
r
k
表
示
01
分
别
表
示
是
否
还
有
病
毒
,
而
d
p
[
m
a
r
k
]
表
示
最
小
代
价
!
那么这道题好像有后效性,那么我们可以用
SPFA
S
P
F
A
来跑
位运算:
考验大家的其实就是位运算的能力:
我们有一个
mask_have[i]:=表示必须有哪一些病毒
mask_not[i]:=表示必须没有那些病毒
那么我们判断只要
这样:
// "~" 就是取反的标记,即二进制的 0 -> 1 , 1 -> 0
if((mask_not[i] & (~stand)) != mask_not[i]) continue;
if((mask_have[i] & stand ) != mask_have[i]) continue;
代码:
#pragma GCC optimize(3)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#define N 25
#define M 115
#define INF 0x3f3f3f3f
#define P pair<int,int>
using namespace std;
int n, m, a[M], b[M], c[M], dp[1 << (N - 2)], mask_have[M], mask_not[M];
int vis[1 << (N - 2)], kill[M], bring[M];
char s1[M][N], s2[M][N];
std::queue<P> G;
inline void init(int x)
{
for(register int i = n - 1; i >= 0; --i)
{
switch(s1[x][i])
{
case '+': mask_have[x] |= 1 << i; break;
case '-': mask_not[x] |= 1 << i; break;
}
switch(s2[x][i])
{
case '+': bring[x] |= 1 << i; break;
case '-': kill[x] |= 1 << i; break;
}
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(b, 0, sizeof b);
memset(c, 0, sizeof c);
for(register int i = 1; i <= m; ++i)
{
scanf("%d%s%s", a + i, s1[i], s2[i]);
init(i);
}
memset(dp, INF , sizeof dp);
dp[(1 << n) - 1] = 0; vis[(1 << n) - 1] = 1;
G.push(P( (1 << n) - 1 , 0));
while( !G.empty() )
{
P now = G.front(); G.pop();
int stand = now.first;
vis[stand] = 0;
for(register int i = 1; i <= m; ++i)
{
if((mask_not[i] & (~stand)) != mask_not[i]) continue;
if((mask_have[i] & stand ) != mask_have[i]) continue;
int to = (stand & (~kill[i])) | bring[i];
if(dp[to] <= dp[stand] + a[i]) continue;
dp[to] = dp[stand] + a[i];
if(!vis[to])
{
vis[to] = true;
G.push(P(to , dp[to]));
}
}
}
printf("%d\n", dp[0] == INF ? 0 : dp[0]);
return 0;
}