zoukankan      html  css  js  c++  java
  • floyd+动态规划 hdu-4571-Travel in time

    题目链接:

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

    题目大意:

    有n个景点,每个点都有个游玩时间ci,游玩后得到的满意度si。给一个起点s和终点e,两个景点间有条无向边,权值为时间。从起点出发,在给定时间限制下,到达终点,问能获得的最大的满意值,只有游玩了景点才能获得该景点的满意值,并且上个游玩景点的满意度必须大于后一个游玩的景点满意度。

    解题思路:

    图上的dp.

    见到图论就晕啊啊啊。先求出不游玩时,任意两点的到达时间,用floyd求。

    dp[i][j]表示到达第i个点,用时为j时,能到达的最大的满意度。

    本题的关键是先对每个景点的满意度从小到大排序,然后对于第i个景点枚举时间j(从大到小,因为一个景点只能游一次), 在枚举前面的i-1个景点,通过前面的满意度得出当前的满意度。转移方程还是很好写的。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #define eps 1e-6
    #define INF 0x1f1f1f1f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    /*
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    */
    #define Maxn 110
    int dp[Maxn][310]; //dp[i][j]表示到达第i个点花了j时间的能获得的最大满意度
    int dis[Maxn][Maxn]; //任意两点间的距离
    int n,m;
    
    struct Node
    {
       int id,si,ci;
       friend bool operator < (const struct Node &a,const struct Node &b)
       {
          return a.si<b.si; //按满意度从小到大排序
       }
    }node[Maxn];
    
    void floy()
    {
       for(int i=0;i<n;i++)
          for(int j=0;j<n;j++)
          {
             if(i==j)
                dis[i][j]=0; //不游玩的到达时间
             else
                dis[i][j]=INF;
          }
       int a,b,v;
       for(int i=0;i<m;i++)
       {
          scanf("%d%d%d",&a,&b,&v); //注意有重边
          dis[a][b]=dis[b][a]=min(dis[a][b],v);
       }
    
       for(int k=0;k<n;k++) //floyd 不断更新两点间的距离
          for(int i=0;i<n;i++)
             for(int j=0;j<n;j++)
             {
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
             }
       return ;
    }
    
    int main()
    {
       int tt,s,e,t;
       int ca=0;
    
       scanf("%d",&tt);
       while(tt--)
       //while(~scanf("%d%d%d%d%d",&n,&m,&t,&s,&e))
       {
          scanf("%d%d%d%d%d",&n,&m,&t,&s,&e);
          for(int i=0;i<n;i++)
          {
             scanf("%d",&node[i].ci);
             node[i].id=i;
          }
          for(int i=0;i<n;i++)
             scanf("%d",&node[i].si);
          sort(node,node+n);
          floy();
    
          printf("Case #%d:
    ",++ca);
          if(dis[s][e]>t) //起点不能到达终点或到达时间超过了
          {
             puts("0");
             continue;
          }
          memset(dp,-1,sizeof(dp));
          int ans=0;
          for(int i=0;i<n;i++) //初始化
          {
             if(dis[s][node[i].id]+node[i].ci<=t)
             {
                dp[node[i].id][node[i].ci+dis[s][node[i].id]]=node[i].si;
               // dp[node[i].id][dis[node[s].id][node[i].id]]=0;
             }
             if(t-dis[s][node[i].id]-node[i].ci>=dis[node[i].id][e])
                ans=max(ans,node[i].si);
          }
    
          for(int i=1;i<n;i++)
             for(int j=t;j>=0;j--)
             {
                for(int k=0;k<i;k++)
                {
                   int tmp=j-node[i].ci-dis[node[k].id][node[i].id]; //注意是严格大于
                   if(tmp>=0&&node[i].si>node[k].si&&dp[node[k].id][tmp]!=-1)
                      dp[node[i].id][j]=max(dp[node[i].id][j],dp[node[k].id][tmp]+node[i].si);
                }
                if(t-j>=dis[node[i].id][e]) //该点的所有时间都求完了
                   ans=max(ans,dp[node[i].id][j]);
             }
          printf("%d
    ",ans);
       }
       return 0;
    }
    
    




  • 相关阅读:
    两个栈实现队列
    重建二叉树
    最大的K个数
    堆排序
    Android 强制竖屏
    屏蔽输入框的焦点
    Android 全屏显示的方法(不包含状态栏)
    android 布局之scrollview
    clean之后R文件消失
    thinkphp
  • 原文地址:https://www.cnblogs.com/pangblog/p/3260682.html
Copyright © 2011-2022 走看看