1. 程式人生 > >[AIZU 2266]Cache Strategy(最大權區間選擇)

[AIZU 2266]Cache Strategy(最大權區間選擇)

/*
    AIZU 2266
    最小花費=最大節省
    考慮可以節省M-1個球的花費。
    s-1:    (M-1,0)
    i-i+1:  (inf,0)
    a[i]=a[j]時: i-(j-1): (1,-w[a[i]])
    //  全部箱子分成M-1個不動的箱子和一個動的箱子
        連到j-1並不意味著到j的時候完全取出,而是挪到了可以動的箱子,
        這樣子不動的箱子就可以留給j-1秒可能加入的不動點。
        如果i-j連的話,如果在第j-1秒加入一個長時間不動的球那就會把他加入可動的箱子裡。
    1 2 3 1 2 3 M=2
    如果1 4 連, 3 5 連那麼1 3不能共存這樣子不對的。
    1 3連,2 4連,3 5連, 3秒時1 3 可以共存在不同屬性箱子中。

        動 不動 花費
add1         1   10
   2     2   1   20
   3     1   3   30
   1     1   3
   2     2   3   20
   3     2   3
*/

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int inf = 1<<30;
const int mmax = 20000020;
const int nmax = 11100;

int N,M,K;
int w[nmax],a[nmax];
int nex[nmax];

struct Edge{int u,v,cap,cost,nex;};
Edge e[mmax];
int etot=0;
int head[nmax];
int dist[nmax],inq[nmax],pre[nmax],e_used[nmax];
//pre:最短路前向點 e_used:到i點前一個用過的邊
int max_flow,min_cost=0;

void init();
void addedge(int u,int v,int cap,int cost);
bool spfa(int s,int t);
void flow_change(int s,int t);
void mincost_maxflow(int s,int t);

int main(){
    int x,tot=0;
    scanf("%d%d%d",&M,&N,&K);
    for(int i=1;i<=N;i++){
        scanf("%d",&w[i]);
    }
    init();
    for(int i=1;i<=K;i++){
        scanf("%d",&a[i]);
    }

    K=unique(a+1,a+1+K)-a-1;
    memset(nex,-1,sizeof(nex));

    addedge(0,1,M-1,0);
    for(int i=1;i<=K;i++){
        tot+=w[a[i]];
        if(nex[a[i]]!=-1)
            addedge(nex[a[i]],i-1,1,-w[a[i]]);
        nex[a[i]]=i;
        addedge(i,i+1,inf,0);
    }
    mincost_maxflow(0,K);
    printf("%d\n",tot+min_cost);
    return 0;
}

void init(){
    max_flow=min_cost=0;
    etot=1;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v,int cap,int cost){
    //printf("%d %d %d %d\n",u,v,cap,cost);
    e[++etot].u=u;  e[etot].v=v;    e[etot].cap=cap;    e[etot].cost=cost;
    e[etot].nex=head[u];
    head[u]=etot;
    e[++etot].u=v;  e[etot].v=u;    e[etot].cap=0;      e[etot].cost=-cost;
    e[etot].nex=head[v];
    head[v]=etot;
}
bool spfa(int s,int t){
    for(int i=s;i<=t;i++)dist[i]=inf;
    memset(inq,0,sizeof(inq));
    memset(pre,-1,sizeof(pre));

    queue<int> q;
    dist[s]=0;
    q.push(s);
    inq[s]=1;

    while(!q.empty()){
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int i=head[u];i!=-1;i=e[i].nex){
            int v=e[i].v;
            if(e[i].cap>0&&dist[v]>dist[u]+e[i].cost){
                dist[v] = dist[u]+e[i].cost;
                pre[v] = u;
                e_used[v] = i;
                if(!inq[v]){
                    inq[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return pre[t]!=-1;
}
void flow_change(int s,int t){
    int u,f=inf;
    for(u=t; u!=s; u=pre[u]){
        f=min(f,e[e_used[u]].cap);
    }
    max_flow+=f;
    for(u=t; u!=s; u=pre[u]){
        e[e_used[u]].cap -= f;
        e[e_used[u]^1].cap += f;
        min_cost += f*e[e_used[u]].cost;
    }
}
void mincost_maxflow(int s,int t){
    while(spfa(s,t)){
        flow_change(s,t);
    }
}