传送门啊啊啊啊啊啊啊啊啊

话说这题不需要网络流…

是一道很简单的最短路状压

每 个 位 置 上 有 没 有 病 毒 可 以 用 01 表 示 , 所 以 当 前 状 态 可 以 表 示 为 二 进 制 每个位置上有没有病毒可以用01表示,所以当前状态可以表示为二进制 01,

每 个 节 点 二 进 制 通 过 某 些 补 丁 通 向 另 一 个 节 点 , 这 就 是 边 每个节点二进制通过某些补丁通向另一个节点,这就是边 ,

所 以 可 以 用 最 短 路 来 做 所以可以用最短路来做

但 是 由 于 边 太 多 了 , 所 以 不 加 边 但是由于边太多了,所以不加边 ,

跑 s p f a 的 时 候 直 接 枚 举 补 丁 看 看 是 否 有 边 跑spfa的时候直接枚举补丁看看是否有边 spfa

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
const int inf=1e9;
int n,m;
string s;
int f1[109],f2[109],b1[109],b2[109],r[109],vis[maxn];
struct edge{
	int to,nxt,w;
}d[maxn];int head[maxn],cnt=1,dis[1<<21];
void add(int u,int v,int w){
	d[++cnt]=(edge){v,head[u],w},head[u]=cnt;
}
void spfa(int s)
{
	for(int i=0;i<=(1<<n);i++)	dis[i]=inf;
	dis[s]=0;
	queue<int>q;
	q.push( s );
	while( !q.empty() )
	{
		int u=q.front(); q.pop();
		vis[u]=0;
		for(int j=1;j<=m;j++)
		{
			if( (u&b1[j])!=b1[j] )	continue;
			if( u&b2[j] )	continue;
			//修复f1,增加f2
			int x= (u&(~f1[j] ) ); //消除了这些错误
			x|=f2[j];//增加了这些错误
			if( dis[u]+r[j]<dis[x] )
			{
				dis[x]=dis[u]+r[j];
				if( !vis[x] )	vis[x]=1,q.push(x);
			}
		}
	}
}
int main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
	{
		cin >> r[i];
		cin >> s;
		for(int j=0;j<n;j++)
			if( s[j]=='+' )	b1[i]+=(1<<j);
			else if( s[j]=='-' )	b2[i]+=(1<<j);
		cin >> s;
		for(int j=0;j<n;j++)
			if( s[j]=='+' )	f2[i]+=(1<<j);
			else if( s[j]=='-' )	f1[i]+=(1<<j);		
	}
	spfa( (1<<n)-1 );
	if( dis[0]==inf )	dis[0]=0;
	cout << dis[0];
}