It’s not a Bug, it’s a Feature!(UVa-658) :
问题描述
题目简述
大意是:现在有一个n个bug都存在的程序,需要给这个程序打补丁修复这所有n个bug,一共有m个补丁可以选择,每个补丁可以使用多次。补丁需要在特定的程序状态下使用,使用后程序的bug状态改变,每个补丁都有运行时长。现在需要求出最短可以修复这n个bug的时长。
输入/输出格式
输入格式:
The input contains several product descriptions. Each description starts with a line containing two
integers n and m, the number of bugs and patches, respectively. These values satisfy 1 ≤ n ≤ 20 and
1 ≤ m ≤ 100. This is followed by m lines describing the m patches in order. Each line contains an
integer, the time in seconds it takes to apply the patch, and two strings of n characters each.
The first of these strings describes the bugs that have to be present or absent before the patch can
be applied. The i-th position of that string is a ‘+’ if bug bi has to be present, a ‘-’ if bug bi has to be
absent, and a ‘0’ if it doesn’t matter whether the bug is present or not.
The second string describes which bugs are fixed and introduced by the patch. The i-th position of
that string is a ‘+’ if bug bi
is introduced by the patch, a ‘-’ if bug bi
is removed by the patch (if it was
present), and a ‘0’ if bug bi
is not affected by the patch (if it was present before, it still is, if it wasn’t,
is still isn’t).
The input is terminated by a description starting with n = m = 0. This test case should not be
processed.
大意是第一行输入n和m代表bug数和补丁数。接下来m行每行3个数,分别代表补丁运行时长,可以加补丁的程序状态,加补丁之后的程序状态(其中“+”代表没有bug,“-”代表有bug,“0”代表有没有bug都无所谓)输入数据有多组,以0 0结束。
输出格式:
For each product description first output the number of the product. Then output whether there is
a sequence of patches that removes all bugs from a product that has all n bugs. Note that in such a
sequence a patch may be used multiple times. If there is such a sequence, output the time taken by the
fastest sequence in the format shown in the sample output. If there is no such sequence, output ‘Bugs
cannot be fixed.’.
Print a blank line after each test case.
大意是:如果可以修复输出修复时间,不能修复输出‘Bugs
cannot be fixed.’。每组之间的输出需要额外输出一个空行。
样例
输入样例:
3 3
1 000 00-
1 00- 0-+
2 0-- -++
4 1
7 0-0+ ----
0 0
输出样例:
Product 1
Fastest sequence takes 8 seconds.
Product 2
Bugs cannot be fixed.
问题分析
解题思路
总体来说题目含义还是比较明显的,求出一个从初始状态到终止状态的最短路长度。状态之间的转移是通过补丁来的。进而可以发现,n个bug的可能状态共有2^n个,但是补丁的数量却很少,最多只有100个。因此,必然有很多状态是一定不会出现的。因此,这个题可以枚举补丁,确定每一步的可能的转移状态。从而大大减少运算。另外由于没有负权边,使用dijkstra算法即可。
参考代码
#include <iostream>
#include <queue>
#include <string>
#include <vector>
#include <cstring>
using namespace std;
const int inf=3e8+5;
class patchnode
{
public:
string before;
string after;
int time;
patchnode(string &b,string &a,int t)
{
before=b;
after=a;
time=t;
}
};
class heapnode
{
public:
int bug;
int dist;
bool operator <(const heapnode& h) const
{
return dist>h.dist;
}
};
vector<patchnode> patchs;
priority_queue<heapnode> pq;
int d[1<<20];
int vis[1<<20];
int m,n;
void init()
{
while(!pq.empty()) pq.pop();
patchs.clear();
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
}
int dijkstra()
{
heapnode start;
start.bug=(1<<n)-1;
start.dist=0;
pq.push(start);
d[start.bug]=0;
while(!pq.empty())
{
heapnode t=pq.top();
pq.pop();
if(t.bug==0) return t.dist;
if(vis[t.bug]==1) continue;
vis[t.bug]=1;
for(int i=0;i<m;i++)
{
bool can=true;
for(int j=0;j<n;j++)
{
if(patchs[i].before[j]=='-'&&(t.bug&1<<j))
{
can=false;
break;
}
if(patchs[i].before[j]=='+'&&!(t.bug&1<<j))
{
can=false;
break;
}
}
if(!can) continue;
heapnode next;
next.bug=t.bug;
next.dist=t.dist+patchs[i].time;
for(int j=0;j<n;j++)
{
if(patchs[i].after[j]=='-')
{
next.bug&=~(1<<j);
}
if(patchs[i].after[j]=='+')
{
next.bug|=1<<j;
}
}
if(next.dist<d[next.bug])
{
d[next.bug]=next.dist;
pq.push(next);
}
}
}
return -1;
}
int main()
{
int T=0;
while(1)
{
scanf("%d %d",&n,&m);
if(n==0&&m==0) break;
init();
for(int i=1;i<=m;i++)
{
string a,b;
int t;
cin>>t>>b>>a;
patchnode p(b,a,t);
patchs.push_back(p);
}
int ans=dijkstra();
printf("Product %d\n", ++T);
if(ans<0) printf("Bugs cannot be fixed.\n\n");
else printf("Fastest sequence takes %d seconds.\n\n", ans);
}
return 0;
}
心得体会
总体而言是一个dijkstra的比较常规的问题,但是在节点状态上做了一些改变。总体来说思路上还是不难想的。另外就是位运算比较生疏,想了好久。还是练习的太少了。