AOJ 2266 Cache Strategy(费用流)

【题目链接】 http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2266

【题目大意】

  有M个桶,N个球,球编号为1到N,每个球都有重量w_i。
  给出一个长K的数列,数列由球的编号构成。开始的时候,桶都是空的。
  接着我们从前往后从数列中取出一个数a_j,执行如下操作:
  如果球a_j已经存在于某一个桶中,那么什么也不干,花费为0,继续。
  如果任何桶中都没有a_j,那么找一个桶放a_j,
  如果该桶里还有球,那么取出原来的球,将a_j放进去。
  这种操作的花费是a_j的重量w_a_j,与桶以及原来的球没关系。
  求最小花费?

【题解】

  我们先假设我们只有一个桶,那么答案就是权值总和,
  然后我们考虑一下如何节省开支,多出来的m-1个桶可以让我们保留一些序号
  一直到下一个相同序号,就节省下了这个序号的费用,
  那这样,我们就得到了这个桶在这个时间区段,被这个序号所占用的信息
  我们将每个桶需要保留到下一个相同需要需要的时间区段整理成一个线段集合,
  那我们只要求出这些线段在最多相交m-1次的情况下能够得到的最大权值和,
  就是我们可以节省的最大开支了。

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
using namespace std;
const int INF=0x3f3f3f3f;
typedef long long LL;
struct edge{
    int to,cap,cost,rev;
    edge(int to,int cap,int cost,int rev):to(to),cap(cap),cost(cost),rev(rev){}
};
const int MAX_V=10010;
int V,dist[MAX_V],prevv[MAX_V],preve[MAX_V];
vector<edge> G[MAX_V];
void add_edge(int from,int to,int cap,int cost){
    G[from].push_back(edge(to,cap,cost,G[to].size()));
    G[to].push_back(edge(from,0,-cost,G[from].size()-1));
}
int min_cost_flow(int s,int t,int f){
    int res=0;
    while(f>0){
        fill(dist,dist+V,INF);
        dist[s]=0;
        bool update=1;
        while(update){
            update=0;
            for(int v=0;v<V;v++){
                if(dist[v]==INF)continue;
                for(int i=0;i<G[v].size();i++){
                    edge &e=G[v][i];
                    if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
                        dist[e.to]=dist[v]+e.cost;
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        update=1;
                    }
                }
            }
        }
        if(dist[t]==INF)return -1;
        int d=f;
        for(int v=t;v!=s;v=prevv[v]){
            d=min(d,G[prevv[v]][preve[v]].cap);
        }f-=d;
        res+=d*dist[t];
        for(int v=t;v!=s;v=prevv[v]){
            edge &e=G[prevv[v]][preve[v]];
            e.cap-=d;
            G[v][e.rev].cap+=d;
        }
    }return res;
}
void clear(){for(int i=0;i<=V;i++)G[i].clear();}
const int MAX_N=10010;
int M,N,K,w[MAX_N],lst[MAX_N],a[MAX_N];
int solve(){
    for(int i=1;i<=N;i++)scanf("%d",&w[i]);
    for(int i=1;i<=K;i++)scanf("%d",&a[i]);
    int cnt=unique(a+1,a+K+1)-(a+1);
    int res=0;
    memset(lst,0,sizeof(lst));
    V=cnt+1; clear();
    for(int i=1;i<=cnt;i++){
        res+=w[a[i]];
        if(lst[a[i]])add_edge(lst[a[i]],i-1,1,-w[a[i]]);
        lst[a[i]]=i;
    }for(int i=1;i<cnt;i++)add_edge(i,i+1,INF,0);
    printf("%d\n",res+min_cost_flow(1,cnt,M-1));
}
int main(){
    while(~scanf("%d%d%d",&M,&N,&K))solve();
    return 0;
}
时间: 2024-10-12 04:58:40

AOJ 2266 Cache Strategy(费用流)的相关文章

Aizu Aoj 2266 (费用流

题目(原文是日语): Google Code Jam区域赛上,坐在右前方的男人ID叫lyrically.东京大学时代的记忆中,记得有个朋友也用类似的ID.不过我的朋友都是萌妹子,我记忆中的 lyrically不仅算法扎实,封装也很强,能一下子给出问题的正解.比如,对我们写得不好的程序也能优化到AC的程度.她说,程序优化时,对缓存池的 利用特别重要. 那么问题来了,现在请你优化下面的缓存池模型: 有M个桶,N个球,球编号为1到N,每个球都有重量w_i.然后给出一个长K的数列,数列由球的编号构成.开

POJ 2677 旅行商问题 双调dp或者费用流

Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3408   Accepted: 1513 Description John Doe, a skilled pilot, enjoys traveling. While on vacation, he rents a small plane and starts visiting beautiful places. To save money, John must

【网络流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,费用为人和房子之间的距离. 这样一来,跑一