题意
想法
顺着做网络流24题看到的 起初原本以为是费用流
后来看到(n <= 20)..
状压走起 这题状压还是很明显的,(b1,b2,f1,f2)都明显压缩,初始状态((1 << n) - 1) 目标状态(0)
这题因为点数太多,直接建边的话空间代价太大,我们选择对每个点都跑一个(m)次的枚举
当现在的状态(now)满足((nowquad andquad b1[i])quad ==quad b1[i]quad andquad (nowquad andquad b2[i])quad ==quad 0),(i)补丁是合法的
可以变为(((nowquad orquad f1[i])quad xorquad f1[i])quad orquad f2[i])
然后跑(spfa)和(dij)都行
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long //注意数据范围 可以状压
using std::queue;
ll n,m;
ll b1[200],b2[200],f1[200],f2[200],v[200];
ll minn[(1 << 20) + 10];
bool vis[(1 << 20) + 10];
queue<ll>QWQ;
void spfa(){
memset(minn,0x7f,sizeof(minn));
memset(vis,0,sizeof(vis));
ll now = (1 << n) - 1;
minn[now] = 0;
QWQ.push(now);
while(!QWQ.empty()){
now = QWQ.front();
//std::cout<<now<<std::endl;
QWQ.pop();
vis[now] = 0;
for(int i = 1;i <= m;++i){
ll to = ((now | f1[i]) ^ f1[i]) | f2[i];
//std::cout<<to<<" "<<((now & b1[i]) == b1[i] && (now & b2[i]) == 0)<<std::endl;
if((now & b1[i]) == b1[i] && (now & b2[i]) == 0 && minn[to] > minn[now] + v[i]){
minn[to] = minn[now] + v[i];
if(!vis[to])vis[to] = 1,QWQ.push(to);
}
}
}
}
int main(){
scanf("%lld%lld",&n,&m);
for(int i = 1;i <= m;++i){
char a[100],b[100];
scanf("%lld%s%s",&v[i],a,b);
for(int j = 0;j < n;++j){
if(a[j] == '+')
b1[i] |= (1 << j);
if(a[j] == '-')
b2[i] |= (1 << j);
if(b[j] == '-')
f1[i] |= (1 << j);
if(b[j] == '+')
f2[i] |= (1 << j);
}
}
// for(int i = 1;i <= m;++i)
// std::cout<<b1[i]<<" "<<b2[i]<<" "<<f1[i]<<" "<<f2[i]<<std::endl;
spfa();
if(minn[0] <= 20000000000)
std::cout<<minn[0]<<std::endl;
else
std::cout<<0<<std::endl;
}