您的位置:首页 > 其它

洛谷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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: