Aizu Aoj 2266 (费用流

题目(原文是日语):

  Google Code Jam区域赛上,坐在右前方的男人ID叫lyrically。东京大学时代的记忆中,记得有个朋友也用类似的ID。不过我的朋友都是萌妹子,我记忆中的 lyrically不仅算法扎实,封装也很强,能一下子给出问题的正解。比如,对我们写得不好的程序也能优化到AC的程度。她说,程序优化时,对缓存池的 利用特别重要。

那么问题来了,现在请你优化下面的缓存池模型:

有M个桶,N个球,球编号为1到N,每个球都有重量w_i。然后给出一个长K的数列,数列由球的编号构成。开始的时候,桶都是空的。接着我们从前往后从数列中取出一个数a_j,执行如下操作:

如果球a_j已经存在于某一个桶中,那么什么也不干,花费为0,继续。

如果任何桶中都没有a_j,那么找一个桶放a_j,如果该桶里还有球,那么取出原来的球,将a_j放进去。这种操作的花费是a_j的重量w_a_j,与桶以及原来的球没关系。

求最小花费?

题目数据第一行是M N K,接着N行权重,K行编号。

思路:首先这是《挑战程序设计》的费用流部分的练习题。。那么就要从费用流的方向来考虑。我们使用桶子的时候,每个时候一定有一个桶子是要用来装新球的,也就是说这个桶子不是保留的桶子,同时其他桶子可以是空桶,也可以装了东西。之后可能会用到之前的球来减少花费。那么我们只需要考虑最有效的保留方式能节省多少钱。同时最多有m-1个桶是保留的,保留多久呢?保留到下一次遇到相同的球。那么如果选择保留这个桶,这个桶在这个区间内都是不可用的。仔细想想,这不就是书上的例题最大权区间选择吗!(poj 3680).那么问题就是,如何选择最多m-1个相交区间,使得权值和最大。

题目翻译来自:http://www.hankcs.com/program/algorithm/aoj-2266-cache-strategy.html

 

/*
* @author:  Cwind
*/

///#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>

using namespace std;
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps (1e-10)
#define INF (1000000300)
#define clr(x) memset((x),0,sizeof (x))
#define cp(a,b) memcpy((a),(b),sizeof (b))

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
typedef pair<ll,int> D;


const int MAXV=1e4+300;
int V;
const int s=MAXV-1,t=MAXV-2;
struct EDGE{
    int to,cap,cost,next;
}ES[MAXV*10];
int eh;
int h[MAXV];
int dis[MAXV];
int prevv[MAXV],preve[MAXV];
int head[MAXV];
void addedge(int from,int to,int cap,int cost){
    ES[eh].to=to;ES[eh].cap=cap;ES[eh].cost=cost;
    ES[eh].next=head[from];head[from]=eh++;
    ES[eh].to=from;ES[eh].cap=0;ES[eh].cost=-cost;
    ES[eh].next=head[to];head[to]=eh++;
}
bool inq[MAXV];
ll min_cost_flow(int s,int t,int f){
    V=MAXV;//default V size maxed
    ll res=0;
    memset(h,0,sizeof h);
    queue<P> Q;////spfa计算势h
    fill(dis,dis+V,INF);
    dis[s]=0;
    Q.push(P(0,s));
    inq[s]=1;
    while(!Q.empty()){
        P p=Q.front();Q.pop();
        int v=p.se;
        inq[v]=0;
        for(int i=head[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                prevv[e.to]=v;
                preve[e.to]=i;
                if(!inq[e.to]) Q.push(P(dis[e.to],e.to)),inq[e.to]=1;
            }
        }
    }
    for(int v=0;v<V;v++)
        h[v]+=dis[v];
    while(f>0){
        priority_queue<P,vector<P> ,greater<P> >Q;////Dijkstra计算势h
        fill(dis,dis+V,INF);
        dis[s]=0;
        Q.push(P(0,s));
        while(!Q.empty()){
            P p=Q.top();Q.pop();
            int v=p.se;
            if(dis[v]<p.fs) continue;
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                    dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    Q.push(P(dis[e.to],e.to));
                }
            }
        }
        if(dis[t]==INF) return -1;
        for(int v=0;v<V;v++) h[v]+=dis[v];
        int d=f;
        for(int v=t;v!=s;v=prevv[v])
            d=min(d,ES[preve[v]].cap);
        f-=d;
        res+=d*h[t];
        for(int v=t;v!=s;v=prevv[v]){
            EDGE &e=ES[preve[v]];
            e.cap-=d;
            ES[preve[v]^1].cap+=d;
        }
    }
    return res;
}
void clear_G(){
    eh=0;
    memset(head,-1,sizeof head);
}

const int maxn=1e4+300;
int M,N,K;
int a[maxn],w[maxn];
int last[maxn];
int tol;
int hh;
void build(){
    for(int i=1;i<hh;i++){
        tol+=w[a[i]];
        if(last[a[i]])
            addedge(last[a[i]],i-1,1,-w[a[i]]);
        last[a[i]]=i;
    }
    for(int i=1;i<hh-1;i++)
        addedge(i,i+1,INF,0);
}
int main(){
    freopen("/home/slyfc/CppFiles/in","r",stdin);
    //freopen("/home/slyfc/CppFiles/out","w",stdout);
    clear_G();
    cin>>M>>N>>K;
    for(int i=1;i<=N;i++)
        scanf("%d",&w[i]);
    for(int i=1;i<=K;i++)
        scanf("%d",&a[i]);
    hh=unique(a+1,a+K+1)-a;
    build();
    int ans=min_cost_flow(1,hh-1,M-1);
    cout<<tol+ans<<endl;
    return 0;    
}
View Code

 

 

 

你可能感兴趣的:(Aizu Aoj 2266 (费用流)