设为首页 加入收藏

TOP

aizu2266-Cache Strategy 最小费用最大流,区间权值最大
2019-05-12 14:38:48 】 浏览:101
Tags:aizu2266-Cache Strategy 最小 费用 最大 区间

这题转化成区间限制权值最大问题,类似于poj3680;我们回顾下吧 orz首先poj3680意思是给出n个区间,每个区间有自己的
权值,使得选出一些区间,使得权值和最大但是不能有点被超过k个区间覆盖。首先,每个权值可以是费用当中用
负值表示,建图方式是首先把所有点按x坐标由小到达排序,于是只看这些点(2*n个,离散下),起点到最左点建容量为
k,cost为0的边,对于每个点都向后面一个点建一个容量为k,cost=0的边,对于每个区间内部,从左端点建一个指向右端点
容量为1(表示只能选一次咯),cost为-w【i】,这样求得的最小费用既是答案。那么看看此题orz首先花费要最少,刚才求的是权值最大那怎么办呢。。。其实花费那就是节约的多,于是可以看怎么弄才能节约最多,对于这m个盒子,如果一个盒子能保持一种颜色从x操作到y操作,他们都是x和y颜色和这个保持的一样,那么就是区间了。所以可以用1个盒子来装入新球,其他m-1个盒子用来省钱用hh,

比如 index: 1 2 3 4 5 6
color: 1 2 3 1 2 3
1号颜色在1和4出现,那么可以转化成刚才那题的1->3区间权值为w[1],为什么是1->3而不是1->4呢,是因为,走到index=3的时候
把3号求放入那个装新球的特别的盒子的时候,其实顺便可以把这个盒子当成用来省钱的盒子,而那个省钱用的装着1号的盒子就用来装新球了。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf = (ll)1<<61;
const ll mmax = 200020;
const ll nmax = 200020;

struct Edge
{
    ll u,v,cap,cost,nex;
};
struct Node
{
    ll col,id;
};
Edge e[mmax];
ll n,etot=0;
ll head[nmax];
ll dist[nmax],inq[nmax],pre[nmax],e_used[nmax];
ll nex[nmax];
//pre:最短路前向点 e_used:到i点前一个用过的边
ll max_flow,min_cost=0;
ll w[nmax],a[nmax];
vector<Node> o[nmax];
void init();
void addedge(ll u,ll v,ll cap,ll cost);
bool spfa(ll s,ll t);
void flow_change(ll s,ll t);
void mincost_maxflow(ll s,ll t);
int main()
{
    ll mm,nn,kk,s,t;
    ll all=0;
    init();
    scanf("%lld%lld%lld",&mm,&nn,&kk);
    mm--;
    for(int i=1;i<=nn;i++)
        scanf("%lld",&w[i]);
    for(int i=1;i<=kk;i++)
    {
        scanf("%lld",&a[i]);
    }
    kk=unique(a+1,a+1+kk)-(a+1);
    memset(nex,-1,sizeof(nex));
    for(int i=1;i<=kk;i++)
    {
        if(nex[a[i]]!=-1)
        addedge(nex[a[i]],i-1,1,-w[a[i]]);
        nex[a[i]]=i;
        if(i!=kk)
            addedge(i,i+1,mm,0);
        all+=w[a[i]];
    }
    s=0,t=kk+1;
    n=kk+1;
    addedge(0,1,mm,0);
    addedge(kk,t,mm,0);
    mincost_maxflow(s,t);
    all+=min_cost;
    printf("%lld\n",all);
    return 0;
}

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

void addedge(ll u,ll v,ll cap,ll cost)
{
   // cout<<u<<"->"<<v<<"->"<<cap<<"->"<<cost<<endl;
    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(ll s,ll t)
{
    for(ll i=0; i<=n; i++)dist[i]=inf;
    memset(inq,0,sizeof(inq));
    memset(pre,-1,sizeof(pre));

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

    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        inq[u]=0;
        for(ll i=head[u]; i!=-1; i=e[i].nex)
        {
            ll 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(ll s,ll t)
{
    ll 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(ll s,ll t)
{
    while(spfa(s,t))
    {
        flow_change(s,t);
    }
}
/*
这题转化成区间限制权值最大问题,类似于poj3680;
我们回顾下吧 orz
首先poj3680意思是给出n个区间,每个区间有自己的
权值,使得选出一些区间,使得权值和最大但是不能有点
被超过k个区间覆盖。首先,每个权值可以是费用当中用
负值表示,建图方式是首先把所有点按x坐标由小到达排序,
于是只看这些点(2*n个,离散下),起点到最左点建容量为
k,cost为0的边,对于每个点都向后面一个点建一个容量为k,
cost=0的边,对于每个区间内部,从左端点建一个指向右端点
容量为1(表示只能选一次咯),cost为-w【i】,这样求得的
最小费用既是答案。
那么看看此题orz
首先花费要最少,刚才求的是权值最大那怎么办呢。。。其实
花费那就是节约的多,于是可以看怎么弄才能节约最多,对于这
m个盒子,如果一个盒子能保持一种颜色从x操作到y操作,他们都是
x和y颜色和这个保持的一样,那么就是区间了。所以可以用1个盒子
来装入新球,其他m-1个盒子用来省钱用hh,
比如 index: 1 2 3 4 5 6
     color:  1 2 3 1 2 3
1号颜色在1和4出现,那么可以转化成刚才那题的1->3区间权值为
w[1],为什么是1->3而不是1->4呢,是因为,走到index=3的时候
把3号求放入那个装新球的特别的盒子的时候,其实顺便可以把这个
盒子当成用来省钱的盒子,而那个省钱用的装着1号的盒子就用来装新球了。
*/

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇算法之排序算法 下一篇Dokcer---一门越用越喜欢的技术

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目