主要的难点是把状态转化为二进制表示,下面是二进制的一些用法:
①判定某些位置是否为1,如判定2、4位置为1,则转化为判断x|0101是否等于x。
②判定某些位置是否为0,如判定2、4位置为0,则转化为判断x&1010是否等于x。
③将某些位置转化为1,如2、4位置转化为1,则令x=x|0101。
④将某些位置转化为0,如2、4位置转化为0,则令x=x&1010。
bef[2][i]和aft[2][i]里存的是每个补丁第一个字符串和第二个字符串的信息
for(int j = 0; j < n; j++)
{
if(str1[j] == '+')
bef[1][i] += (1<<j);
if(str1[j] != '-')
bef[0][i] += (1<<j);
if(str2[j] == '+')
aft[1][i] += (1<<j);
if(str2[j] != '-')
aft[0][i] += (1<<j);
}
这段代码要理解透彻,注意,用==来判断“+”,而用!=来判断“-”。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#define INF 0x3f3f3f3f
using namespace std;
int n, m;
int bef[2][105];
int aft[2][105];
int d[1<<21+1];
int vis[1<<21+1];
int cost[100*100+5];
queue<int> que;
void spfa()
{
while(!que.empty()) que.pop();
int ans = (1<<n)-1;
que.push(ans);
for(int i = 0; i < ans; i++)
{
vis[i] = 0;
d[i] = INF;
}
vis[ans] = 1;
d[ans] = 0;
while(!que.empty())
{
int front = que.front();
que.pop();
vis[front] = 0;
for(int i = 0; i < m; i++)
{
if((front|bef[1][i])==front && (front&bef[0][i])==front)
{
int temp;
temp = front|aft[1][i];
temp = temp&aft[0][i];
if(d[front]+cost[i] < d[temp])
{
d[temp] = d[front]+cost[i];
if(!vis[temp])
{
que.push(temp);
vis[temp] = 1;
}
}
}
}
}
if(d[0] == INF) printf("Bugs cannot be fixed.\n");
else printf("Fastest sequence takes %d seconds.\n",d[0]);
}
int main()
{
//freopen("ztest.txt","r",stdin);
//freopen("zans.txt","w",stdout);
int t = 1;
while(scanf("%d%d", &n, &m) && (n || m))
{
memset(bef, 0, sizeof(bef));
memset(aft, 0, sizeof(aft));
if(t != 1) printf("\n");
printf("Product %d\n", t++);
for(int i = 0; i < m; i++)
{
scanf("%d", &cost[i]);
string str1, str2;
cin >> str1 >> str2;
// cout << str1 << endl;
// cout << str2 << endl;
for(int j = 0; j < n; j++)
{
if(str1[j] == '+')
bef[1][i] += (1<<j);
if(str1[j] != '-')
bef[0][i] += (1<<j);
if(str2[j] == '+')
aft[1][i] += (1<<j);
if(str2[j] != '-')
aft[0][i] += (1<<j);
}
}
spfa();
}
printf("\n");
return 0;
}