zoukankan      html  css  js  c++  java
  • 1500. Pass Licenses 夜

    http://acm.timus.ru/problem.aspx?space=1&num=1500

    bfs 状态压缩  对应K N M

    有 1<<K 个状态代表那种类型的边用 或不用

    对每个状态就行bfs求解最短路 若可以搜到或者所求值一定不是最优  则包含这个状态的状态就不用求了 这个剪枝很重要

    代码及其注释:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<vector>
    #include<set>
    #include<map>
    #include<string>
    #include<queue>
    #include<stack>
    #include <iomanip>
    using namespace std;
    #define LL long long
    #define sint short int
    const int INF=0x3f3f3f3f;
    //priority_queue<int,vector<int>,greater<int> >qt;
    const int N=31;
    int side[N][N];//两个点之间有哪几种边 用状态压缩表示
    bool can[1<<20];//这种状态要不要求
    int qu[N];//队列
    int ans,K;//最优个数 和状态
    bool to[N];//广搜时看能不能到底某个点
    int n,m,k;
    bool bfs(int w)//返回true 则包含这个状态的状态就不用搜了
    {
        int sum=0;
        for(int i=0;i<k;++i)
        if(w&(1<<i))
        ++sum;
        if(sum>=ans)//一定不是最优
        return true;
        memset(to,false,sizeof(to));
        to[0]=true;
        qu[0]=0;
        int L=0,R=1;
        while(L<R)
        {
            int x=qu[L++];
            for(int i=1;i<n;++i)
            {
                if(!to[i]&&(w&side[x][i]))
                {
                    if(i==1)
                    {ans=sum;K=w;return true;}//更新答案
                    to[i]=true;
                    qu[R++]=i;
                }
            }
        }
        return false;
    }
    int main()
    {
        //freopen("data.in","r",stdin);
        while(scanf("%d %d %d",&k,&n,&m)!=EOF)
        {
            memset(can,true,sizeof(can));
            memset(side,0,sizeof(side));
            while(m--)
            {
                int l,r,w;
                scanf("%d %d %d",&l,&r,&w);
                side[l][r]=(side[l][r]|(1<<w));//记录两点之间有哪几种边
                side[r][l]=(side[r][l]|(1<<w));
            }
            ans=INF;
            int h=(1<<k)-1;
            for(int i=1;i<=h;++i)
            {
                if(can[i])
                {
                    if(bfs(i))
                    {
                        for(int l=i;l<=h;l=((l+1)|i))//把包含这个状态的状态标记 不用再求
                        can[l]=false;
                    }
                }
            }
            printf("%d\n",ans);
            bool first=true;
            for(int i=0;i<k;++i)
            if(K&(1<<i))
            {
                if(first)
                {printf("%d",i);first=false;}
                else
                printf(" %d",i);
            }
            printf("\n");
        }
    }
    

      

  • 相关阅读:
    技术人生:码农必读
    DDD:子龙关于聚合的总结
    DDD:DomainEvent、ApplicationEvent、Command
    VisualStudio:【外部工具】之代码生成器
    技术人生:为你的决定负责
    DDD:通过四色原型来理解聚合
    DDD:贫血模型和领域模型的一些思考
    TDD:第一次真正使用TDD的感受
    DDD:领域层服务的设计原则
    技术人生:大出着眼 小处着手
  • 原文地址:https://www.cnblogs.com/liulangye/p/2802043.html
Copyright © 2011-2022 走看看