luogu P2761 软件补丁问题(最短路)
题目大意
T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。
换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误,而不包含 B2[i]中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]。另外,每个补丁都耗费一定的时间。
试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。
解题思路
对bug的情况状态压缩,建最多 2 20 2^{20} 220,根据补丁建边从二进制各位均为1,跑到二进制各位均为0跑个最短路即可.不知道为什么放到网络流24题里
AC代码
#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
struct MOVE{
string in,out;
ll w;
friend bool operator<(MOVE a,MOVE b){
return a.w<b.w;
}
}mov[105];
struct node{
int id;ll w;
node(int id=0,ll w=0):id(id),w(w){}
friend bool operator<(node a,node b){
return a.w>b.w;
}
};
int n,m;
priority_queue<node> q;
ll dis[1<<21];int vis[1<<21];
bool check(int id,string in)
{
for(int i=0;i<n;i++)
{
if(in[i]=='-'){
if(((id>>i)&1)) return false;
}else if(in[i]=='+'){
if(!((id>>i)&1)) return false;
}else{
continue;
}
}
return true;
}
int change(int id,string out)
{
for(int i=0;i<n;i++){
if(out[i]=='-'){
id=(~((~id)|(1<<i)));
}
else if(out[i]=='+'){
id|=(1<<i);
}
}
return id;
}
void Dijkstra()
{
int beg=0;
for(int i=0;i<n;i++) beg|=(1<<i);
for(int i=0;i<(1<<21);i++) dis[i]=inf;
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
q.push(node(beg,0)),dis[beg]=0;
while(!q.empty())
{
node s=q.top();
q.pop();
int id=s.id;
if(vis[id]) continue;
vis[id]=1;
if(dis[id]!=s.w) continue;
for(int i=1;i<=m;i++)
{
if(check(s.id,mov[i].in))
{
int nxtid=change(s.id,mov[i].out);
if(dis[nxtid]>dis[s.id]+mov[i].w)
{
dis[nxtid]=dis[s.id]+mov[i].w;
q.push(node(nxtid,dis[nxtid]));
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
cin>>mov[i].w>>mov[i].in>>mov[i].out;
}
Dijkstra();
int obj=0;
//if(tot) printf("\n");
if(dis[obj]==inf) printf("0\n");
else printf("%lld\n",dis[obj]);
cout<<endl;
}