poj1482 & hdu1818 It's not a Bug, It's a Feature!(bfs+状态压缩)

It's not a Bug, It's a Feature!
Time Limit: 5000MS Memory Limit: 30000K
Total Submissions: 1205 Accepted: 456

Description

It is a curious fact that consumers buying a new software product generally do not expect the software to be bug-free. Can you imagine buying a car whose steering wheel only turns to the right? Or a CD-player that plays only CDs with country music on them? Probably not. But for software systems it seems to be acceptable if they do not perform as they should do. In fact, many software companies have adopted the habit of sending out patches to fix bugs every few weeks after a new product is released (and even charging money for the patches). 
Tinyware Inc. is one of those companies. After releasing a new word processing software this summer, they have been producing patches ever since. Only this weekend they have realized a big problem with the patches they released. While all patches fix some bugs, they often rely on other bugs to be present to be installed. This happens because to fix one bug, the patches exploit the special behavior of the program due to another bug. 

More formally, the situation looks like this. Tinyware has found a total of n bugs B = {b1, b2, ..., bn} in their software. And they have released m patches p1, p2, ..., pm. To apply patch pi to the software, the bugs Bi + in B have to be present in the software, and the bugs Bi - in B must be absent (of course Bi + ∩ Bi - = Φ). The patch then fixes the bugs Fi - in B (if they have been present) and introduces the new bugs Fi + in B (where, again, Fi +∩ Fi - = Φ). 

Tinyware's problem is a simple one. Given the original version of their software, which contains all the bugs in B, it is possible to apply a sequence of patches to the software which results in a bug- free version of the software? And if so, assuming that every patch takes a certain time to apply, how long does the fastest sequence take?

Input

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. 

Output

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.

Sample Input

3 3
1 000 00-
1 00- 0-+
2 0-- -++
4 1
7 0-0+ ----
0 0

Sample Output

Product 1
Fastest sequence takes 8 seconds.

Product 2
Bugs cannot be fixed.

Source


题目大意:有n个bug,现在给m个补丁,每个补丁有作用时间,每个补丁工作有一定的前提条件,当某些bug必须存在,某些bug必须不存在的时候该补丁才能工作,补丁作用完后会修复一些bug也会产生新的bug。求这m个补丁修复好n个bug要的最短时间。

题目分析:bfs+状态压缩+优先队列。设bug存在置为状态1,bug被修复了置为状态0,初态是n个1,终态是n个0,由于n<=20,可以压缩到一个整数里面,那么初始状态就是2^n - 1,终态就是0。把每个补丁工作的条件用2个整数表示,can1表示该补丁工作时必须存在的补丁的位置,can2表示该补丁工作使不能存在补丁的位置,都用1标识出来。补丁作用完后也用2个整数表示修复后的状态,fixed表示补丁工作完后被修复的bug的位置,unfixed表示补丁工作完后新产生bug的位置。这样可以直接用位操作判断补丁是否能工作以及补丁工作完后的状态。不过这样写完后提交很可能会wa,这是因为这m个补丁要修复n个bug可能有多种方式,所需要的时间也就不同,由于补丁给的顺序不同,所以最优解不一定先产生,所以单纯的用单调队列还不够,具体的可以看看后面给的例子。判重的时候可以记录下到达该状态的时候所需要的步数,如果再次到达该状态可能步数更少些,应该再次入队,这点很重要,跪了一下午。。。。

详情请见代码:

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int flag[2000000];
int n,m;
struct node
{
    int step,state;
    bool operator < (const struct node &b)const
    {
        return step > b.step;
    }
}ss,now;

struct nd
{
    int can1,can2;
    int fixed,unfixed;
    int sec;
}patch[105];
priority_queue<node> q;
int bfs()
{
    int i;
    ss.state = (1<<n) - 1;
    memset(flag,-1,sizeof(flag));
    ss.step = 0;
    int ret = -1;
    flag[ss.state] = 0;
    q.push(ss);
    while(!q.empty())
    {
        now = q.top();
        q.pop();
        if(now.state == 0)
        {
            ret = now.step;
            break;
        }  
        for(i = 1;i <= m;i ++)
        {
            int t1 = now.state & patch[i].can1;
            int t2 = now.state & patch[i].can2;
            if(t1 == patch[i].can1 && t2 == 0)//can
            {
                ss.state = now.state;
                ss.state |= patch[i].unfixed;//1
                ss.state &= (~patch[i].fixed);//0
                ss.step = now.step + patch[i].sec;
                if(flag[ss.state] == -1 || flag[ss.state] > ss.step)
                {
                    flag[ss.state] = ss.step;
                    q.push(ss);
                }
            }
        }
    }
    while(!q.empty())
        q.pop();
    return ret;
}
int nextint()
{
    char c;
    int ret = 0;
    while(isspace(c = getchar()))
        ;
    ret = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return ret;
}
int main()
{
    int i,j;
    int cas = 0;
    char c;
    while(scanf("%d%d",&n,&m) && (m + n))
    {
        for(i = 1;i <= m;i ++)
        {
            patch[i].sec = nextint();
            while(isspace(c = getchar()))
                ;
            j = 1;
            patch[i].can1 = patch[i].can2 = 0;
            while(!isspace(c))
            {
                if(c == '0')
                    c = getchar();
                else
                {
                    if(c == '+')
                        patch[i].can1 |= 1<<(n - j);
                    else
                        patch[i].can2 |= 1<<(n - j);
                    c = getchar();
                }
                j ++;
            }
            while(isspace(c = getchar()))
                ;
            j = 1;
            patch[i].fixed = patch[i].unfixed = 0;
            while(!isspace(c))
            {
                if(c == '0')
                    c = getchar();
                else
                {
                    if(c == '-')
                        patch[i].fixed |= 1<<(n - j);
                    else
                        patch[i].unfixed |= 1<<(n - j);
                    c = getchar();
                }
                j ++;
            }
        }
        int ans = bfs();
        printf("Product %d\n",++cas);
        if(ans == -1)
            printf("Bugs cannot be fixed.\n\n");
        else
            printf("Fastest sequence takes %d seconds.\n\n",ans);
    }
    return 0;
}
//203MS	8108K   //140MS  4980K
/*
3 4
8 000 ---
2 000 00-
2 00- 0--
2 0-- ---
3 3
1 000 00-
1 00- 0-+
2 0-- -++
4 1
7 0-0+ ----
4 1
3 0000 ----
20 20
4 00000000000000000000 0000000000000000000-
16 0000000000000000000- 000000000000000000-+
14 000000000000000000-- 00000000000000000-++
12 00000000000000000--- 0000000000000000-+++
13 0000000000000000---- 000000000000000-++++
19 000000000000000----- 00000000000000-+++++
4 00000000000000------ 0000000000000-++++++
6 0000000000000------- 000000000000-+++++++
12 000000000000-------- 00000000000-++++++++
1 00000000000--------- 0000000000-+++++++++
13 0000000000---------- 000000000-++++++++++
3 000000000----------- 00000000-+++++++++++
12 00000000------------ 0000000-++++++++++++
19 0000000------------- 000000-+++++++++++++
13 000000-------------- 00000-++++++++++++++
18 00000--------------- 0000-+++++++++++++++
1 0000---------------- 000-++++++++++++++++
3 000----------------- 00-+++++++++++++++++
17 00------------------ 0-++++++++++++++++++
18 0------------------- -+++++++++++++++++++
1 1
2 - -
1 1
3 + +
1 1
4 + -
1 1
5 - +
0 0
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值