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;
}

时间: 2024-09-30 20:51:01

Aizu Aoj 2266 (费用流的相关文章

【网络流24题】No.19 负载平衡问题 (费用流)

[题意] G 公司有 n 个沿铁路运输线环形排列的仓库, 每个仓库存储的货物数量不等. 如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入文件示例input.txt517 9 14 16 4 输出文件示例output.txt11 [分析] 其实我觉得这题可以贪心啊..n^2贪心??.没细想.. 打的是费用流.. 大概这样建图: 懒得写了..凌乱之美.. 求满流费用.. 1 #include<cstdio> 2 #include<cstdlib&

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

hdu 2448 Mining Station on the Sea【网络费用流】

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 732 Problem Description The ocean is a treasure house of resources and the development

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)

[BZOJ3502]PA2012 Tanie linie Description n个数字,求不相交的总和最大的最多k个连续子序列. 1<= k<= N<= 1000000. Sample Input 5 2 7 -3 4 -9 5 Sample Output 13 题解:跟1150和2151差不多. 我们先做一些预处理,因为连续的正数和连续的负数一定是要么都选要么都不选,所以可以将它们合并成一个数,同时区间中的零以及左右两端的负数没有意义,可以将它们删掉.然后我们得到的序列就变成:正-

POJ 2195 Going Home(费用流)

http://poj.org/problem?id=2195 题意: 在一个网格地图上,有n个小人和n栋房子.在每个时间单位内,每个小人可以往水平方向或垂直方向上移动一步,走到相邻的方格中.对每个小人,每走一步需要支付1美元,直到他走入到一栋房子里.每栋房子只能容纳一个小人. 计算出让n个小人移动到n个不同的房子需要支付的最小费用. 思路: 源点和每个人相连,容量为1,费用为0. 汇点和每栋房子相连,容量为1,费用为0. 每个人和每栋房子相连,容量为1,费用为人和房子之间的距离. 这样一来,跑一

洛谷P3381——费用流模板题

嗯..随便刷了一道费用流的模板题....来练练手. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int h[5210],d[5210],used[5210],que[100010],last[5210]; int k=1,INF=0x7fffffff,ans1=0,ans2=0; inline int read(){ int t=1,num=0; char c=ge

BZOJ1877 SDOI2009 晨跑 费用流

题意:给定一张有向图,求1到N:1.最多有多少条不相交的路径  2.在第一问的基础上,求所有路径的最小距离和 题解:拆点之后费用流裸题 #include <queue> #include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namesp