• 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);
    }
    
    
  • 相关阅读:
    第一份随笔
    慢哈希算法
    彩虹表
    基于Wireshark验证网站口令认证传输方案
    electron学习笔记2
    基于原型的软件需求获取
    《小学四则运算练习软件》结对项目报告
    201571030109 小学四则运算练习软件项目报告
    201571030109 《构建之法》速读
    个人学期总结
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9852271.html
Copyright © 2020-2023  润新知