zoukankan      html  css  js  c++  java
  • hdu 4284 Travel 夜

    http://acm.hdu.edu.cn/showproblem.php?pid=4284

    这题后台数据相当强呀 

    思路:先用flody  求得任意两点间的最短距离

    然后再用 状态压缩+DP

    dist [ i ] [ j ]  表示已经到 i 状态压缩表示的城市 拿到证件 打工 而且现在在 第 j 个要去的城市  这种情况下剩余的最多钱

    不断更新  最后看是否有满足条件 去过所以要去的城市 而且还能回到原点的  状态

    代码及其注释:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    
    #define LL long long
    
    using namespace std;
    
    const int N=103;
    const int H=16;
    const int INF=0x0fffffff;
    int dist[1<<16][H];//此状态剩余最多钱
    int d[N][N];//最短路
    struct node
    {
        int k,c,d;
    }mem[H];//要去的城市相关信息
    bool cmp(node x,node y)//按城市序号排序 主要是让原点 在 0 位置
    {
        return x.k<y.k;
    }
    int main()
    {
        //freopen("data.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n,m,money,h,K;;
            scanf("%d %d %d",&n,&m,&money);
            for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
            {
                if(i==j)d[i][j]=0;
                else d[i][j]=INF;//初始化
            }
            while(m--)
            {
                int i,j,p;
                scanf("%d %d %d",&i,&j,&p);
                d[i][j]=d[j][i]=min(d[i][j],p);
            }
            scanf("%d",&h);
            int have1=false;
            for(int i=0;i<h;++i)
            {
                scanf("%d %d %d",&mem[i].k,&mem[i].c,&mem[i].d);
                if(mem[i].k==1)
                have1=true;
            }
            if(!have1)//如果原点不在则将原点加入  这样不会影响最终结果 而且便于运算
            {
                mem[h].c=mem[h].d=0;
                mem[h].k=1;++h;
            }
            sort(mem,mem+h,cmp);
            for(int l=1;l<=n;++l)
            for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
            if(d[i][j]>d[i][l]+d[l][j])
            d[i][j]=d[i][l]+d[l][j];//求最短路
            memset(dist,-1,sizeof(dist));
            K=(1<<h)-1;
            dist[0][0]=money;//在没有去过任何城市时 在第0个要去的城市(原点)时所有钱
            for(int i=0;i<K;++i)
            {
                for(int j=0;j<h;++j)//i 和 j表示的顺序不能变 因为更新时是想i 变大的方向更新
                {
                    if(dist[i][j]==-1)
                    continue;
                    for(int l=0;l<h;++l)
                    {
                        int temp=i|(1<<l);
                        if(temp==i)//已经去过 拿证件 打工
                        continue;
                        int more=dist[i][j]-d[mem[j].k][mem[l].k]-mem[l].d;//看是否可以成功到达 并且拿到证件
                        if(more<0)
                        continue ;
                        dist[temp][l]=max(dist[temp][l],more+mem[l].c);//更新
                    }
                }
            }
            bool ans=false;
            for(int i=0;i<h;++i)
            if(dist[K][i]>=d[mem[i].k][mem[0].k])//去过所有要去的城市 而且能回到原点
            {ans=true;break;}
            if(ans)
            printf("YES\n");
            else
            printf("NO\n");
        }
        return 0;
    }
    
  • 相关阅读:
    C++ 如何重复利用一个内存地址块
    C与C++在const用法上的区别
    C++ 与设计模式学习(其一)
    C/C++ 关于生成静态库(lib)/动态库(dll)文件如何使用(基于windows基础篇)
    c/c++----网站及其后门(CGI应用程序)
    C/C++深度copy和浅copy
    C/C++ 一段代码区分数组指针|指针数组|函数指针|函数指针数组
    C/C++ 如何劫持别人家的命令||函数||程序(只能对于window而言)
    C++继承与派生(原理归纳)
    Linux下如何查看自己的服务器有没有无线网卡
  • 原文地址:https://www.cnblogs.com/liulangye/p/2685211.html
Copyright © 2011-2022 走看看