洛谷P2761:软件补丁问题
2018-02-01 22:46
369 查看
题目大意
给出n个错误与m种不同的补丁,每种补丁当且仅当b1[i]包含当前状态的的错误,且b2[i]不包含当前状态下的
错误(b1[i]与b2[1]是两个集合,题目给出)。
每个补丁都有他自己的运行时间,i补丁会修复在f1[i]里面的错误,同时也会带来f2[i]里面的错误。(因为这个,
题目从简单的二分图最大匹配问题变得很复杂。至少在你没有看出来是最短路求解之前)
解法
很多人都说这题不应该出在网络流24题里面,因为这题用网络流做会很复杂(因为我不懂),所以大多数A了这题的人跟我一样,都是用最短路+状态压缩求解,其实也很好解释。
用queue[i]来作为最短路的队列,里面存的是一个状态,因为总错误只有20个,所以对于第k个错误来说,如果已经被处理过了,那么倒数第k位就是0;否则就是1,相当于加上1<<(k-1);
很多人会说,你讲那么快,我怎么会看的懂?妖怪吧。。
那我们来举一个例子比如说现在一共有5个错误,1错误被处理掉了,3错误也被处理掉了,那么状态就是11010(26)。没错,n<=20,所以这个东西转成10进制之后不过才100多万。你可以像我一样开一个循环队列或者是系统的队列都行,希望大家能听懂咯。。
每一次迭代一遍补丁,找到满足条件的补丁后,算出目标状态,判断当前状态所用时间+补丁所用时间<原来花费时间,那么就把原来时间替换掉(=当前状态所用时间+补丁所用时间),加进队列,继续操作,最后判断一下0(及所有都被处理掉时)状态是否被查找过,如果是,那么输出0状态时间,否则就输出0。完了。希望大家喜欢,下面的是c++代码。
#include<cstdio>
#include<cstdlib>
#include<cstring>
int time[110];
int n,m;
int b1[110],b2[110],f1[110],f2[110];
int queue[1050010];
int d[1050010];
int st,ed;
void bfs()
{
memset(d,63,sizeof(d));
st=1,ed=2;
queue[st]=(1<<n)-1;
d[(1<<n)-1]=0;
while(st!=ed)
{
for(int i=1;i<=m;i++)
{
if((queue[st] & b1[i]) == b1[i] && (queue[st] & b2[i]) == 0)
{
int op=(queue[st] & (~f1[i]));
op=(op | f2[i]);
if(d[queue[st]]+time[i]<d[op])
{
d[op]=d[queue[st]]+time[i];
queue[ed]=op;
ed++;
if(ed>105000) ed=1;
}
}
}
st++;
if(st>105000) st=1;
}
}
int main()
{
char s[25];
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&time[i]);
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='+') b1[i]+=(1<<(j-1));
if(s[j]=='-') b2[i]+=(1<<(j-1));
}
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='-') f1[i]+=(1<<(j-1));
if(s[j]=='+') f2[i]+=(1<<(j-1));
}
}
bfs();
if(d[0]==1061109567)
printf("0\n");
else
printf("%d",d[0]);
}
给出n个错误与m种不同的补丁,每种补丁当且仅当b1[i]包含当前状态的的错误,且b2[i]不包含当前状态下的
错误(b1[i]与b2[1]是两个集合,题目给出)。
每个补丁都有他自己的运行时间,i补丁会修复在f1[i]里面的错误,同时也会带来f2[i]里面的错误。(因为这个,
题目从简单的二分图最大匹配问题变得很复杂。至少在你没有看出来是最短路求解之前)
解法
很多人都说这题不应该出在网络流24题里面,因为这题用网络流做会很复杂(因为我不懂),所以大多数A了这题的人跟我一样,都是用最短路+状态压缩求解,其实也很好解释。
用queue[i]来作为最短路的队列,里面存的是一个状态,因为总错误只有20个,所以对于第k个错误来说,如果已经被处理过了,那么倒数第k位就是0;否则就是1,相当于加上1<<(k-1);
很多人会说,你讲那么快,我怎么会看的懂?妖怪吧。。
那我们来举一个例子比如说现在一共有5个错误,1错误被处理掉了,3错误也被处理掉了,那么状态就是11010(26)。没错,n<=20,所以这个东西转成10进制之后不过才100多万。你可以像我一样开一个循环队列或者是系统的队列都行,希望大家能听懂咯。。
每一次迭代一遍补丁,找到满足条件的补丁后,算出目标状态,判断当前状态所用时间+补丁所用时间<原来花费时间,那么就把原来时间替换掉(=当前状态所用时间+补丁所用时间),加进队列,继续操作,最后判断一下0(及所有都被处理掉时)状态是否被查找过,如果是,那么输出0状态时间,否则就输出0。完了。希望大家喜欢,下面的是c++代码。
#include<cstdio>
#include<cstdlib>
#include<cstring>
int time[110];
int n,m;
int b1[110],b2[110],f1[110],f2[110];
int queue[1050010];
int d[1050010];
int st,ed;
void bfs()
{
memset(d,63,sizeof(d));
st=1,ed=2;
queue[st]=(1<<n)-1;
d[(1<<n)-1]=0;
while(st!=ed)
{
for(int i=1;i<=m;i++)
{
if((queue[st] & b1[i]) == b1[i] && (queue[st] & b2[i]) == 0)
{
int op=(queue[st] & (~f1[i]));
op=(op | f2[i]);
if(d[queue[st]]+time[i]<d[op])
{
d[op]=d[queue[st]]+time[i];
queue[ed]=op;
ed++;
if(ed>105000) ed=1;
}
}
}
st++;
if(st>105000) st=1;
}
}
int main()
{
char s[25];
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&time[i]);
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='+') b1[i]+=(1<<(j-1));
if(s[j]=='-') b2[i]+=(1<<(j-1));
}
scanf("%s",s+1);
for(int j=1;j<=n;j++)
{
if(s[j]=='-') f1[i]+=(1<<(j-1));
if(s[j]=='+') f2[i]+=(1<<(j-1));
}
}
bfs();
if(d[0]==1061109567)
printf("0\n");
else
printf("%d",d[0]);
}
相关文章推荐
- 洛谷P2761 软件补丁问题(状压dp)
- 洛谷 P2761 软件补丁问题 【spfa】
- 网络流24题之T12 软件补丁问题
- 软件补丁问题([网络流24题之12])[状态压缩+最短路径]
- 解决局域网内微软防病毒软件不能更新补丁的问题
- [Luogu P2761] [网络流24题] 软件补丁问题
- [网络流24题] 软件补丁问题
- 【网络流24题----12】软件补丁问题
- Libre 6009 「网络流 24 题」软件补丁 / Luogu 2761 软件安装问题 (最短路径,位运算)
- 网络流24题之软件补丁问题
- P2761 软件补丁问题
- 网络流二十四题之十二 —— 软件补丁问题(BUG)
- [置顶]Win2012R2的一个Bug安装群集后可能引发的软件崩溃问题及相应补丁
- 【网络流24题】软件补丁问题(最短路)
- [网络流24题] 软件补丁问题
- [luoguP2761] 软件补丁问题(状压最短路)
- 网络流24题——软件补丁问题(spfa+位运算)
- P2761 软件补丁问题
- 【网络流24题】软件补丁问题
- 洛谷P2761 软件补丁问题