zoukankan      html  css  js  c++  java
  • [每日小结] 浅谈堆模拟费用流

    前言:最近写了很多关于堆模拟费用流的题,说通俗一点就是用(堆+后悔操作)去实现贪心。

    例题:

    例1:POJ-2431 Expedition

    解析:这题应该是这类套路里面最简单的一道题了, 每经过一个加油站相当于拥有了在这个加油站加油的权力,那么将这个加油站的油加入堆,一旦以后油不够用了,就从堆中取出最大值加油,直到终点。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define N 100010
    using namespace std;
    
    int a[N],b[N];
    
    struct Node {
      int a,b;
      bool operator < (const Node &x) const {
        return a<x.a;
      }
    }p[N];
    
    priority_queue<int> Q;
    
    int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    int main() {
      int n=gi(),ans=0,pos=0,L,oil;
      for(int i=1; i<=n; i++) p[i].a=gi(),p[i].b=gi();
      sort(p+1,p+n+1);
      L=gi(),oil=gi();
      for(int i=n; i>=0; i--) {
        a[i]=L-p[i].a,b[i]=p[i].b;
        int d=a[i]-pos;
        while(oil-d<0) {
          if(Q.empty()) {puts("-1");return 0;}
          oil+=Q.top(),Q.pop(),ans++;     
        }
        oil-=d,pos=a[i],Q.push(b[i]);
      }
      printf("%d", ans);
      return 0;
    }
    

    例2:K10.31-D1T2 angry

    解析:这题仔细分析一下就可以发现与上一题很类似,如果用零钱会花费c[i]%100的零钱,如果用整钱会100-c[i]%100,可以发现每次都要减去一个c[i]%100,但是用整钱的话就相当于赔了愤怒值但赚了100块钱,于是每次贪心尽量地出零钱,零钱不够用了就在堆中找愤怒值最小的那一天用整钱。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define N 100010
    using namespace std;
    
    ll ans;
    int w[N],c[N],out[N][2];
    
    struct Node {
      int i,v;
      bool operator < (const Node &x) const {
        return v>x.v;
      }
    };
    
    priority_queue<Node> Q;
    
    int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    int main() {
      int n=gi(),m=gi();
      for(int i=1; i<=n; i++) c[i]=gi();
      for(int i=1; i<=n; i++) w[i]=gi();
      for(int i=1; i<=n; i++) {
        if(c[i]%100==0) out[i][0]=c[i]/100,out[i][1]=0;
        else {
          if(m>=c[i]%100) {
    	m-=c[i]%100;
    	out[i][0]=c[i]/100;
    	out[i][1]=c[i]%100;
    	Q.push((Node){i,w[i]*(100-c[i]%100)});
          }
          else {
    	Q.push((Node){i,w[i]*(100-c[i]%100)});
    	Node u=Q.top(); Q.pop();
    	ans+=w[u.i]*(100-c[u.i]%100);
    	m+=100-c[i]%100;
    	out[u.i][0]=(c[u.i]+99)/100,out[u.i][1]=0;
    	if(u.i!=i) out[i][0]=c[i]/100,out[i][1]=c[i]%100;
          }
        }
      }
      printf("%lld
    ", ans);
      for(int i=1; i<=n; i++) {
        printf("%d %d
    ", out[i][0],out[i][1]);
      }
      return 0;
    }
    

    例3:K11.1-D2T2 trade

    解析:首先这题很容易想到dp,但是只能做到1000,对于(10^5)就需要用到更高效的解法——堆模拟费用流。
    具体到这道题来说就是一旦有利润那么就直接算利润,如果在后面的利润更大,那么用后悔操作可以获得更大的利润。
    后悔操作:
    1、当前股票比堆顶小,买入。
    2、当前股票比堆顶大,卖出,并将当前股票入堆两次,一次相当于是用来实现“后悔”,方便算出将别人卖出的代价,另一次则是将自己卖出。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define ll long long
    #define RG register
    #define N 100010
    using namespace std;
    
    int a[N];
    priority_queue<int,vector<int>,greater<int> > Q;
    
    inline int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    int main() {
      ll ans=0;
      int T=gi(),n,tot=0;
      while(T--) {
        n=gi(),ans=0;
        for(RG int i=1; i<=n; i++) a[i]=gi();
        while(!Q.empty()) Q.pop();
        for(RG int i=1; i<=n; i++) {
          Q.push(a[i]); 
          if(Q.top()<a[i]) {
    	ans+=a[i]-Q.top();
    	Q.pop();
    	Q.push(a[i]);
          }
        }
        printf("Case #%d: %lld
    ", ++tot,ans);
      }
    }
    
  • 相关阅读:
    转载 jenkins执行selenium 测试 浏览器不显示解决方法
    jmeter用beanshell调用自己写的jar进行MD5加密
    深入理解Spring MVC 思想
    springmvc和json整合配置方法
    getFragmentManager和getChildFragmentManager
    android
    HTTP 请求头与请求体
    Android中ImnageView 中如何让图片拉伸显示?
    ExecutorService 的理解与使用
    SpringMVC源码分析系列
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7795783.html
Copyright © 2011-2022 走看看