最短路。把
n
n
n 个错误压缩到一个 int
里,建图的时候枚举一下选择哪一个补丁,如果可以的话就向新的错误状态建立一条边。然后直接跑最短路就可以了。
初始状态是 2 n − 1 2^n-1 2n−1。终止状态是 0 0 0。
#include <bits/stdc++.h>
using namespace std;
const int N = 21;
int ht[N], dis[1 << N];
bool vis[1 << N];
char s1[N * N][N * N], s2[N * N][N * N];
signed main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
cin >> ht[i];
scanf("%s%s", s1[i], s2[i]);
}
memset(dis, 0x3f, sizeof dis);
dis[(1ll << n) - 1] = 0;
vis[(1ll << n) - 1] = true;
queue<int> q;
q.push((1ll << n) - 1);
while (q.size())
{
int f = q.front();
q.pop();
vis[f] = false;
for (int i = 0; i < m; i++)
{
int g = f;
bool flag = true;
int l1 = strlen(s1[i]);
for (int j = 0; j < l1; j++)
{
if (s1[i][j] == '+' && !(g >> j & 1))
{
flag = false;
break;
}
if (s1[i][j] == '-' && (g >> j & 1))
{
flag = false;
break;
}
}
if (flag)
{
int l2 = strlen(s2[i]);
for (int j = 0; j < l2; j++)
{
if (s2[i][j] == '+')
g |= (1 << j);
if (s2[i][j] == '-' && (g >> j & 1))
g -= (1 << j);
}
if (dis[g] > dis[f] + ht[i])
{
dis[g] = dis[f] + ht[i];
if (!vis[g])
{
vis[g] = true;
q.push(g);
}
}
}
}
}
if (dis[0] > 1e9)
cout << "0\n";
else
cout << dis[0] << '\n';
return 0;
}