Description
$T$公司发现其研制的一个软件中有$n$个错误,随即为该软件发放了一批共$m$个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。
换句话说,对于每一个补丁$i$,都有$2$个与之相应的错误集合$B_1[i],B_2[i]$,使得仅当软件包含$B_1[i]$中的所有错误,而不包含$B_2[i]$中的任何错误时,才可以使用补丁$i$。补丁$i$将修复软件中的某些错误$F_1[i]$,而同时加入另一些错误$F_2[i]$。另外,每个补丁都耗费一定的时间。
试利用$T$公司提供的$m$个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。
Input
第$1$行有$2$个正整数$n,m$,$n$表示错误总数,$m$表示补丁总数。
接下来$m$行给出了$m$个补丁的信息。每行包括一个正整数,表示运行补丁程序$i$所需时间,以及$2$个长度为$n$的字符串,中间用一个空格符隔开。第$1$个字符串中,如果第$k$个字符$b_k$为“+”,则表示第$k$个错误属于$B_1[i]$,若为“-”,则表示第$k$个错误属于$B_2[i]$,若为“$0$”,则第$k$个错误既不属于$B_1[i]$也不属于$B_2[i]$,即软件中是否包含第$k$个错误并不影响补丁$i$的可用性。第$2$个字符串中,如果第$k$个字符$b_k$为“-”,则表示第$k$个错误属于$F_1[i]$,若为“+”,则表示第$k$个错误属于$F_2[i]$,若为“$0$”,则第$k$个错误既不属于$F_1[i]$也不属于$F_2[i]$,即软件中是否包含第$k$个错误不会因使用补丁$i$而改变。
Output
一行一个整数,表示最短耗时。如果问题无解,则输出$0$。
Sample Input
3 3
1 000 00-
1 00- 0-+
2 0-- -++
Sample Output
8
HINT
$1;leq;n;leq;20, 1;leq;m;leq;100$
Solution
将每种错误情况二进制状压表示,可转移的连一条权值为时间的边,跑最短路.
#include<cmath> #include<ctime> #include<queue> #include<stack> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 25 #define M 105 #define K 1048576 using namespace std; typedef long long ll; struct graph{ int nxt,to, w; }e[N*K]; int g[K],b1[M],b2[M],f1[M],f2[M],t[M],dis[K],n,m,cnt; bool inq[K]; char c[N]; queue<int> q; inline void addedge(int x,int y,int w){ e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].w=w; } inline int spfa(int u){ for(int i=0;i<K;++i) dis[i]=-1; q.push(u);inq[u]=true;dis[u]=0; while(!q.empty()){ u=q.front();q.pop();inq[u]=false; for(int i=g[u];i;i=e[i].nxt){ if(dis[e[i].to]<0||dis[u]+e[i].w<dis[e[i].to]){ dis[e[i].to]=dis[u]+e[i].w; if(!inq[e[i].to]){ inq[e[i].to]=true;q.push(e[i].to); } } } } return max(0,dis[0]); } inline void Aireen(){ scanf("%d%d",&n,&m); for(int l=1;l<=m;++l){ scanf("%d",&t[l]); scanf("%s",c); for(int i=0;i<n;++i) if(c[i]=='+') b1[l]+=(1<<i); else if(c[i]=='-') b2[l]+=(1<<i); scanf("%s",c); for(int i=0;i<n;++i) if(c[i]=='-') f1[l]+=(1<<i); else if(c[i]=='+') f2[l]+=(1<<i); } for(int i=0;i<(1<<n);++i) for(int j=1;j<=m;++j) if((i&b1[j])==b1[j]&&!(i&b2[j])&&(i&f1[j])) addedge(i,i-(i&f1[j])+f2[j]-(i&f2[j]),t[j]); printf("%d ",spfa((1<<n)-1)); } int main(){ freopen("bug.in","r",stdin); freopen("bug.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }