zoukankan      html  css  js  c++  java
  • 洛谷P2483 Bzoj1975 [SDOI2010]魔法猪学院

    题目描述

    iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练。经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界的世界本原有了很多的了解:众所周知,世界是由元素构成的;元素与元素之间可以互相转换;能量守恒……。

    能量守恒……iPig 今天就在进行一个麻烦的测验。iPig 在之前的学习中已经知道了很多种元素,并学会了可以转化这些元素的魔法,每种魔法需要消耗 iPig 一定的能量。作为 PKU 的顶尖学猪,让 iPig 用最少的能量完成从一种元素转换到另一种元素……等等,iPig 的魔法导猪可没这么笨!这一次,他给 iPig 带来了很多 1 号元素的样本,要求 iPig 使用学习过的魔法将它们一个个转化为 N 号元素,为了增加难度,要求每份样本的转换过程都不相同。这个看似困难的任务实际上对 iPig 并没有挑战性,因为,他有坚实的后盾……现在的你呀!

    注意,两个元素之间的转化可能有多种魔法,转化是单向的。转化的过程中,可以转化到一个元素(包括开始元素)多次,但是一但转化到目标元素,则一份样本的转化过程结束。iPig 的总能量是有限的,所以最多能够转换的样本数一定是一个有限数。具体请参看样例。

    输入输出格式

    输入格式:

     

    第一行三个数 N、M、E 表示iPig知道的元素个数(元素从 1 到 N 编号)、iPig已经学会的魔法个数和iPig的总能量。

    后跟 M 行每行三个数 si、ti、ei 表示 iPig 知道一种魔法,消耗 ei 的能量将元素 si 变换到元素 ti 。

     

    输出格式:

     

    一行一个数,表示最多可以完成的方式数。输入数据保证至少可以完成一种方式。

     

    输入输出样例

    输入样例#1:
    4 6 14.9
    1 2 1.5
    2 1 1.5
    1 3 3
    2 3 1.5
    3 4 1.5
    1 4 1.5
    
    输出样例#1:
    3

    说明

    有意义的转换方式共4种:

    1->4,消耗能量 1.5
    1->2->1->4,消耗能量 4.5
    1->3->4,消耗能量 4.5
    1->2->3->4,消耗能量 4.5

    显然最多只能完成其中的3种转换方式(选第一种方式,后三种方式仍选两个),即最多可以转换3份样本。 如果将 E=14.9 改为 E=15,则可以完成以上全部方式,答案变为 4。

    数据规模

    占总分不小于 10% 的数据满足 N <= 6,M<=15。

    占总分不小于 20% 的数据满足 N <= 100,M<=300,E<=100且E和所有的ei均为整数(可以直接作为整型数字读入)。

    所有数据满足 2 <= N <= 5000,1 <= M <= 200000,1<=E<=107,1<=ei<=E,E和所有的ei为实数。

    A星算法。先从终点SPFA到起点估价,然后A星宽搜(用堆维护花费最少的方案),每到终点就累加方案。

    然而这题神TM卡priority_queue,用stl会MLE,非要手写堆才能过。

    (根据dalao所说,这题省选原题限制内存256M,放到OJ上限制就改成了64M)

    但是洒家不想向手写势力低头!

    各种花式卡时,刷了一页评测记录,终于从50卡到80,从80卡到90,从90卡到AC。

    在!这!停!顿!时间总计1小时45分钟

    感到肝力上升了……

      1 /*by SilverN*/
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<cmath>
      7 #include<queue>
      8 using namespace std;
      9 const double eps=1e-7;
     10 int read(){
     11     int x=0,f=1;char ch=getchar();
     12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     14     return x*f;
     15 }
     16 const int mxn=200100;
     17 struct edge{
     18     int v,nxt;
     19     double dis;
     20 }e[mxn],mp[mxn];
     21 int hd1[5002],hd2[5002];
     22 int mct1=0,mct2=0;
     23 inline void add_edge(int u,int v,double dis){
     24     e[++mct1].v=v;e[mct1].nxt=hd1[u];e[mct1].dis=dis;hd1[u]=mct1;
     25     return;
     26 }
     27 inline void add_edge2(int u,int v,double dis){
     28     mp[++mct2].v=v;mp[mct2].nxt=hd2[u];mp[mct2].dis=dis;hd2[u]=mct2;
     29     return;
     30 }
     31 int n,m;
     32 double E;
     33 //
     34 
     35 double dis[5002];
     36 struct target{
     37     unsigned short int u;
     38     float w;
     39 };
     40 bool operator< (target aa,target an)
     41 {return aa.w+dis[aa.u]>an.w+dis[an.u];}
     42 priority_queue<target>tp;
     43 //
     44 bool inq[5002];
     45 int head=0,tl=1;
     46 int q[5010];
     47 void SPFA(){
     48     memset(dis,127,sizeof dis);
     49     q[++head]=n;
     50     dis[n]=0;
     51     inq[n]=1;
     52     int i,j;
     53     while(head!=tl+1){
     54         int u=q[head++];if(head==5010)head=0;
     55         for(register int i=hd2[u];i;i=mp[i].nxt){
     56             int v=mp[i].v;
     57             if(dis[v]>dis[u]+mp[i].dis){
     58                 dis[v]=dis[u]+mp[i].dis;
     59                 if(!inq[v]){
     60                     inq[v]=1;
     61                     tl++;if(tl==5010)tl=0;
     62                     q[tl]=v;
     63                 }
     64             }
     65         }
     66         inq[u]=0;
     67     }
     68 }
     69 int ans=0;
     70 void gt(){//A*
     71     int i,j;
     72     tp.push((target){1,0});
     73     while(!tp.empty()){
     74         target x=tp.top();tp.pop();
     75         if(x.u==n){
     76             E-=x.w;
     77 
     78 //            if(smm>E)break;
     79             if(E+eps<0)return;
     80             ans++;
     81             continue;
     82         }
     83         if(x.w+dis[x.u]>E)continue;
     84         for(register int i=hd1[x.u];i;i=e[i].nxt){
     85             tp.push( (target){e[i].v,x.w+e[i].dis} );
     86         }
     87     }
     88     return;
     89 }
     90 //
     91 int main(){
     92     int i,j;
     93     scanf("%d%d%f",&n,&m,&E);
     94     int u,v;
     95     float d;
     96     for(register int i=1;i<=m;i++){
     97 //        scanf("%d%d%lf",&u,&v,&d);
     98         u=read();
     99         v=read();
    100         scanf("%f",&d);
    101         add_edge(u,v,d);
    102         add_edge2(v,u,d);
    103     }
    104     SPFA();
    105     gt();
    106     printf("%d
    ",ans);
    107     return 0;
    108 }
  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/5922479.html
Copyright © 2011-2022 走看看