効果の件名:
長さを持っている(N- \)\すべての「+」、および開始または「+」文字列- 「」のみを含む\(M \)の操作を、各操作は時間を持っているC(\ \)、2つだけを含む' - '、 '+'、 '0'文字列の\(\)と、文字列\(B \)、文字列と文字列があれば\(\)に等しい(ストリング\(\)の位置「0」ではない)、次に文字列は、文字列を変更することができる\(B \) (文字列\(\)「0」の位置ではない)、各操作消費する(\ C)を\。Q.どのように、少なくとも、文字列全体のために多くの時間「 - 」。
本体:
以降\(N- \のLeq 20 \である)、圧縮の状態を使用することができ、 ' - '及び'+'は、それぞれ'0'と'1'の図。元の問題は、我々は、元の文字列と文字列かどうかを判断するためにビット操作を使用することができる\(Aは\)に等しいです。
if((u & b1[i]) == b1[i] && (u & b2[i]) == 0)
(b1[i]
そして、b2[i]
それはテキストに記載されています。)
元の質問によると、まだ文字列に文字列でも(B \)\:
((u | f1[i]) ^ f1[i]) | f2[i]
(f1[i]
そして、f2[i]
それはまた、テキストに記載されています。)
これらは私がSPFAを使用し、この問題を解決するための最短経路を得ることができます。
コード:
const int N = 110;
int n, m;
int b1[N], b2[N], f1[N], f2[N], TiMe[N];
int dis[1 << 21];
inline void read(int &x)
{
char ch = getchar();
while(ch < '0' || ch > '9')
ch = getchar();
x = ch - 48; ch = getchar();
while(ch >= '0' && ch <= '9')
{
x = x * 10 + (ch - 48);
ch=getchar();
}
}
queue <int> que;
bool vis[1 << 21];
void SPFA()
{
memset(dis, 0x7f, sizeof dis);
dis[(1 << n) - 1] = 0;
que.push((1 << n) - 1);
while (!que.empty())
{
int u = que.front();que.pop();
for (int i = 1; i <= m; i++)
{
if((u & b1[i]) == b1[i] && (u & b2[i]) == 0)
{
int v = ((u | f1[i]) ^ f1[i]) | f2[i];
if(dis[u] + TiMe[i] < dis[v])
{
dis[v] = dis[u] + TiMe[i];
if(!vis[v])
{
que.push(v);
vis[v] = 1;
}
}
}
}
vis[u] = 0;
}
}
int main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
read(n), read(m);
for (int i = 1; i <= m; i++)
{
read(TiMe[i]);
char ch = getchar();
while(ch != '+' && ch != '-' && ch != '0')
ch = getchar();
for(int j = 1; j <= n; ++j)
{
if(ch == '+')
b1[i] += 1 << (j - 1);
if(ch == '-')
b2[i] += 1 << (j - 1);
ch = getchar();
}
while(ch != '+' && ch != '-' && ch != '0')
ch = getchar();
for(int j = 1; j <= n; ++j)
{
if(ch == '-')
f1[i] += 1 << (j - 1);
if(ch == '+')
f2[i] += 1 << (j - 1);
ch = getchar();
}
}
SPFA();
if (dis[0] == dis[(1<<21)-1]) puts("0");
else printf("%d\n", dis[0]);
return 0;
}