Description
T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。
换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误,而不包含 B2[i]中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]。另外,每个补丁都耗费一定的时间。
试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。
Input&Range
第 1 行有 2 个正整数 n 和 m,n 表示错误总数,m表示补丁总数,1<=n<=20, 1<=m<=100。
接下来 m 行给出了 m 个补丁的信息。每行包括一个正整数,表示运行补丁程序 i 所需时间,以及 2 个长度为 n 的字符串,中间用一个空格符隔开。
第 1 个字符串中,如果第 k 个字符 bk 为“+”,则表示第 k 个错误属于 B1[i],若为“-”,则表示第 k 个错误属于 B21[i],若为“0”,则第 k 个错误既不属于 B1[i]也不属于 B2[i],即软件中是否包含第 k 个错误并不影响补丁 i 的可用性。
第 2 个字符串中,如果第 k 个字符 bk为“-”,则表示第 k 个错误属于 F1[i],若为“+”,则表示第 k 个错误属于 F2[i],若为“0”,则第 k 个错误既不属于 F1[i]也不属于 F2[i],即软件中是否包含第 k 个错误不会因使用补丁i 而改变。
Output
程序运行结束时,将总耗时数输出。如果问题无解,则输出 0。
Solution
我们用一个n位二进制数表示当前状态,从左往右数第i位表示第i个软件是否有病毒。可以在每次输入的时候连边跑最短路,但是会超时。所以要把每个二进制数记录下来,spfa的时候把建图和求最短路一起做了=.=
但是有一个地方不明白,当求当前状态向某一状态转移时,为什么不能这样:
int j=i^f1|f2;
正解却是这样:
int j=i&(~f1)|f2;
第二种理解了,就是f1取反之后再与i表示该在的病毒还是在。那我们再回头看第一种,第一种可能是因为输入时有数据会令某个病毒在f1里出现却没有在i中出现,这就导致0^1的出现,把本该是0的地方变成了1,所以wa。
Code
#include<cstdio> #include<cstring> #define int long long using namespace std; int hd,tail=1; int q[1100005]; int dis[1100005]; bool in[1100005]; char a[25],b[25]; int ruanjian[105][8];//1--b1 2--b2 3--f1 4--f2 5--t int n,m,cnt,maxn; void spfa(int s){ dis[maxn-1]=0; q[1]=s; while(hd++<tail){ int u=q[hd]; in[u]=0; for(int i=1;i<=m;i++){ int b1=ruanjian[i][1]; int b2=ruanjian[i][2]; int f1=ruanjian[i][3]; int f2=ruanjian[i][4]; int t=ruanjian[i][5]; if((u&b1)!=b1||(u&b2)) continue; int j=u&(~f1)|f2; if(dis[j]>dis[u]+t){ dis[j]=dis[u]+t; if(!in[j]) in[j]=1,q[++tail]=j; } } } } signed main(){ scanf("%lld%lld",&n,&m);maxn=1<<n; for(int i=0;i<maxn;i++) dis[i]=1234567890; for(int h=1;h<=m;h++){ scanf("%lld",&ruanjian[h][5]); scanf("%s%s",a,b); for(int i=0;i<n;i++){ if(a[i]==‘+‘) ruanjian[h][1]|=1<<i; if(a[i]==‘-‘) ruanjian[h][2]|=1<<i; if(b[i]==‘-‘) ruanjian[h][3]|=1<<i; if(b[i]==‘+‘) ruanjian[h][4]|=1<<i; } } spfa(maxn-1); printf(dis[0]==1234567890?"0":"%lld",dis[0]); return 0; }
原文地址:https://www.cnblogs.com/YoungNeal/p/8476591.html