poj1482(隐式图求最短路)

题目链接


题意:补丁在修正bug时,有时也会引入新的bug。假定有n个潜在的bug m个补丁,每个补丁用两个长度为n的字符串表示,其中字符串的每个位置表示一个bug,第一个串表示打补丁之前的状态('-'表示该bug必须不存在,’+‘表示必须存在,0表示无所谓,第二个串表示打补丁之后的状态(-'表示不存在,’+‘表示存在,0表示不变)。每个补丁都有一个执行时间,你的任务使用最少的时间把一个bug都存在的软件通过打补丁的方式变得没有bug。一个补丁可以打多次。


解法:状压表示每个补丁的存在与否。隐式搜索,会有很多状态根本搜不到,spfa直接搜索即可。对于每次都枚举使用所有的补丁修补并松弛得到的状态。


代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=10100000;
const LL INF=0x3FFFFFFF;
int state[(1<<20)+10];
int n,m;
struct bug
{
    int cost;
    char start[22];
    char end[22];
} bugs[1200];
bool operator<(const bug& a,const bug& b)
{
    return a.cost<b.cost;
}
int que[Max];
bool rem[(1<<20)+10];
int getstate(int st,int j)
{
    for(int i=0; i<n; i++)
    {
        if(bugs[j].start[i]=='-'&&(st&(1<<i)))
            return -1;
        if(bugs[j].start[i]=='+'&&!(st&(1<<i)))
            return -1;
    }
    int re=0;
    for(int i=0; i<n; i++)
    {
        if(bugs[j].end[i]=='+')
            re|=(1<<i);
        if(bugs[j].end[i]=='0')
            re|=st&(1<<i);
    }
    return re;
}
int main()
{
    int kk=1;
    while(cin>>n>>m)
    {
        if(n==0&&m==0)
            break;
        for(int i=0; i<m; i++)
            scanf("%d%s%s",&bugs[i].cost,bugs[i].start,bugs[i].end);
        sort(bugs,bugs+m);
        memset(state,-1,sizeof state);
        memset(rem,0,sizeof rem);
        state[(1<<n)-1]=0;
        rem[(1<<n)-1]=1;
        int left=0,right=1;
        que[0]=(1<<n)-1;
        while(left<right)
        {
            //cout<<left<<endl;
            int t=que[left++];
            for(int i=0; i<m; i++)
            {
                int st=getstate(t,i);
                if(st!=-1&&(state[st]==-1||state[st]>state[t]+bugs[i].cost))
                {
                    state[st]=state[t]+bugs[i].cost;
                    if(!rem[st])
                        que[right++]=st,rem[st]=1;
                }
            }
            rem[t]=0;
        }
        printf("Product %d\n",kk++);
        if(state[0]==-1)
            puts("Bugs cannot be fixed.");
        else
        {
            printf("Fastest sequence takes %d seconds.\n",state[0]);
        }
        cout<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值