zoukankan      html  css  js  c++  java
  • gcd?人生赢家!

    题目背景

    原创:b2019dy
    gcd是一个热爱游戏的人

    题目描述

    gcd最近在玩一个有趣的游戏
    我们把这个游戏抽象成一张图,图上有n个点,我们需要寻找总计m件宝物,它们分布在图上,对于每件宝物而言,将会有一个前置集合S.只有当取得所有前置宝物时,才能获得该宝物。
    gcd拥有一件神器,这件神器具有传送功能,它可以使用k次,可以传送到一个任意节点。
    对于游戏而言,肯定会有额外的成就,这些成就会奖励一定的传送次数,成就的达成是满足集合S的一瞬间。
    现在gcd想知道能最快通关的方法

    输入输出格式

    输入格式:

    第一行:n,m,k
    第二行:s表示成就的数量
    以下s行,num表示需求多少个宝物,然后num个数,为所需宝物编号
    第s+3行:a1​,a2​,⋯as​表示成就的奖励次数
    第s+4行:mp1​,p2​,⋯pm​表示宝物的位置
    第s+5行:e表示边的总数
    以下e行:每行三个数x,y,z表示x与y之间有无向边连接,边权为z.
    以下m行:每行一个数num表示第i个宝物的前置要求数,之后num个数,表示所需宝物编号
    最后一行:st表示起点

    输出格式:

    最少时间

    输入输出样例

    输入样例#1: 复制

    3 2 0
    1
    1 1
    1
    2 3
    3
    1 2 20
    1 3 20
    3 2 1
    0
    0
    1

    输出样例#1: 复制

    20

    输入样例#2: 复制

    3 2 0
    1
    1 1
    1
    2 3
    3
    1 2 1
    1 3 20
    3 2 20
    1 2
    0
    1

    输出样例#2: 复制

    40

    说明

    对于20%的数据,s=0
    对于100%的数据:n≤200,m≤12,k≤4,s≤8,e≤20000
    奖励次数总和不超过8
    数据保证每两个宝物的位置不相同
    可能有重边
    数据保证有解


    就是状压啦
    想到三维状态(f[i][j][k])表示那宝藏状态为(i)时,传送了(j)次,现在在位置(k)时的最少步数
    预处理出每个合法状态和每个合法状态可以由那些状态转移过来
    似乎还是很难用dp状态转移,用记忆化搜索会比较好写


    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define LL long long
    #define M 1000001
    #define max(a,b) ((a)>(b)? (a):(b))
    #define min(a,b) ((a)<(b)? (a):(b))
    
    using namespace std;
    
    int i,m,n,j,k,f[4099][13][13],ss,t,s[20],g,gi[20],p[10001],e,d[201][202],x,y,z,l,q[M],st,w[100001],bl[100001],r[4500][4500],ans=0x3f3f3f3f;
    
    int dp(int now,int bs,int t)
    {
        if(now==(1<<m)-1) ans=min(ans,f[now][bs][t]);
        for(int i=1;i<=r[bl[now]][0];i++)
        {
            int y=0,x=0;
            if(bs>=k) for(int j=1;j<=ss;j++) if((s[j] ^now)==now-s[j])  y+=gi[j];
            int z=r[bl[now]][i]^now;
            while(z) z>>=1,x+=1;
            if(y+k>bs) if(f[r[bl[now]][i]][bs+1][x]>f[now][bs][t]) 
            {
                f[r[bl[now]][i]][bs+1][x]=f[now][bs][t];
                dp(r[bl[now]][i],bs+1,x);
            }
            if(f[r[bl[now]][i]][bs][x]>f[now][bs][t]+d[p[t]][p[x]])
            {
                f[r[bl[now]][i]][bs][x]=f[now][bs][t]+d[p[t]][p[x]];
                dp(r[bl[now]][i],bs,x);
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&k,&ss);
        for(i=1;i<=ss;i++)
        {
            scanf("%d",&t);
            for(t;t;t--)
            {
                scanf("%d",&g);
                s[i]|=1<<(g-1);
            }
        }
        for(i=1;i<=ss;i++) scanf("%d",&gi[i]);
        for(i=1;i<=m;i++) scanf("%d",&p[i]);
        scanf("%d",&e);
        memset(d,0x3f,sizeof(d));
        for(i=1;i<=e;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            d[y][x]=d[x][y]=min(d[x][y],z);
        }
        
        for(l=1;l<=n;l++)
            for(i=1;i<=n;i++)
                for(j=1;j<=n;j++) 
                    if(i!=j) d[j][i]=d[i][j]=min(d[i][l]+d[l][j],d[i][j]);
                    else d[i][j]=0;
    
        for(i=1;i<=m;i++)
        {
            scanf("%d",&t);
            for(j=1;j<=t;j++) 
            {
                scanf("%d",&g);
                q[i]|=1<<(g-1);
            }
        }
    
        scanf("%d",&st);
        for(i=1;i<1<<m;i++)
        {
            g=i; int b=1;
            while(g)
            {
                int h=g & -g, x=0;
                g-=h;
                while(h) x+=1, h>>=1;
                if(i-q[x]!=(i^q[x])) b=0;
                g-=h;
            }
            if(b) w[++w[0]]=i, bl[i]=w[0];
        }
        
        for(i=1;i<=w[0];i++)
        {
            t=w[i];
            while(t)
            {
                g=t & -t;
                if(bl[w[i]-g]) r[bl[w[i]-g]][++r[bl[w[i]-g]][0]]=w[i];
                t-=g;
            }
        }
        memset(f,0x3f,sizeof(f));
        t=1<<(st-1), y=0;
        for(j=1;j<=ss;j++) if(s[j]==t) y+=gi[j];
        for(i=0;i<m;i++)
        {
            t=1<<i, y=0;
            if(q[i+1]) continue;
            f[t][0][i+1]=d[st][p[i+1]];
            dp(t,0,i+1);
             
            if(k+y>=1) 
            {
                f[t][1][i+1]=0;
                dp(t,1,i+1);
            }
        }
        
        printf("%d",ans);
    }
    
    
  • 相关阅读:
    格式化数字,将字符串格式的数字,如:1000000 改为 1 000 000 这种展示方式
    jquery图片裁剪插件
    前端开发采坑之安卓和ios的兼容问题
    页面消息提示,上下滚动
    可以使用css的方式让input不能输入文字吗?
    智慧农村“三网合一”云平台测绘 大数据 农业 信息平台 应急
    三维虚拟城市平台测绘 大数据 规划 三维 信息平台 智慧城市
    农业大数据“一张图”平台测绘 大数据 房产 国土 农业 信息平台
    应急管理管理局安全生产预警平台应急管理系统不动产登记 测绘 大数据 规划 科教 三维 信息平台
    地下综合管廊管理平台测绘 大数据 地下管线 三维 信息平台
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9852271.html
Copyright © 2011-2022 走看看