码迷,mamicode.com
首页 > 其他好文 > 详细

uva658 It's not a Bug, it's a Feature!

时间:2019-11-17 17:46:24      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:复杂   enc   The   搜索   def   ring   name   use   http   

传送门https://vjudge.net/problem/UVA-658

看到这题以为是搜索。不过直接搜索估计会G。

正解是隐式图搜索,(看上去挺像bfs的,实际上就是带着权值的bfs,于是就变成了最短路

隐式图搜索就是在一个没有直接给出边的图上进行图论算法(最短路什么的 现在只碰到了最短路

虽然说没有直接给出边,但是可以通过题目给的条件建边,比如这题就是在状态u的时候,枚举所有补丁,看是否可以使用,使用后状态变为v,那么u->v就可以建边

为什么要隐式图搜索呢?正常每个状态枚举补丁也可以呀。问题就是如果预处理所有边,那么空间上无法接受,而且很多状态根本遇不到,所以没必要先把图预处理好。

因为堆优化dijkstra在跑点的时候每个点只会做一次起点,所以边不会重复计算。这样做时间复杂度为O(m2^n)可以接受

还有一个小难点就是check状态u是否能打上补丁,以及如何求打上补丁后的状态。具体实现见代码。

坑点:每次结果后面要两次换行。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
struct Node
{
    int u,d;
    Node(int u,int d):u(u),d(d){}
    bool operator < (const Node N)const
    {
        return d>N.d;
    }
};
int n,m,t[110],dis[1100000];    //t指打补丁的时间
char s1[110][21],s2[110][21];    //s1打补丁前 s2打补丁后
bool vis[1100000];                //其他都是写dijkstra的辅助数组
struct Solve
{
    int N,M;
    void init(int N,int M)        //初始化
    {
        this->N=N;this->M=M;
        memset(vis,false,sizeof vis);
    }
    bool check(int x,int now)    //状态now能否打上第x个补丁
    {
        int tmp=now;
        for(int i=0;i<N;i++)
        {
            int j=N-i-1;
            if(s1[x][i]!=0)
            {
                if(s1[x][i]==-&&((now>>j)&1)) return false;
                if(s1[x][i]==+&&((now>>j)&1)==0) return false;
            }
        }
        return true;
    }
    void change(int x,int &now)    //状态now打上补丁x后变成什么状态
    {
        for(int i=0;i<N;i++)
        {
            int j=N-i-1;
            if(s2[x][i]==+) now=now|(1<<j);
            if(s2[x][i]==-) now=now&(~(1<<j));
        }
    }
    void showmethedata()        //debug用的函数
    {
        for(int i=0;i<(1<<N);i++)
            printf("%d %d\n",i,dis[i]);
    }
    int dij()                    //dijkstra堆优化板子
    {
        priority_queue<Node>q;
        q.push(Node( (1<<N)-1,0));
        for(int i=0;i<(1<<N);i++)
            dis[i]=1e8;
        dis[(1<<N)-1]=0;
        while(!q.empty())
        {
            Node e=q.top();q.pop();
            if(e.u==0) return dis[0];
            if(vis[e.u]) continue;
            vis[e.u]=true;
            for(int i=1;i<=M;i++)//枚举m个补丁找边
            {
                int v=e.u;
                if(check(i,v))
                {
                    change(i,v);
                    if(t[i]+dis[e.u]<dis[v])
                    {
                        dis[v]=dis[e.u]+t[i];
                        q.push(Node(v,dis[v]));
                    }
                }
            }
        }
        return -1;
    }

}solver;
int main()
{
    int T=0;
//    freopen("out.txt","w",stdout);
    while(scanf("%d%d",&n,&m)==2)
    {
        if(n==0&&m==0) break;
//        if(T) printf("\n");
        solver.init(n,m);
        for(int i=1;i<=m;i++)
            scanf("%d %s %s",&t[i],s1[i],s2[i]);
        printf("Product %d\n",++T);
        int ans=solver.dij();
        if(ans>=0) printf("Fastest sequence takes %d seconds.\n\n",ans);
        else printf("Bugs cannot be fixed.\n\n");
    }
//    system("pause");
}

 

uva658 It's not a Bug, it's a Feature!

标签:复杂   enc   The   搜索   def   ring   name   use   http   

原文地址:https://www.cnblogs.com/tmzengbi/p/11876925.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!