713C

费用流

并没有想出来构图方法 我们设立源汇,其实我们关心的是相邻两个值的差值,如果差值小于0说明需要长高,那么向汇点连边差值,说明需要修改,如果差大于零,那么由源点连边差值,说明可以提供修改空间,再由源点向1和n+1连边inf,因为这两个点是可以无限修改的。然后1-2-3-n+1连双向边,费用为1,容量inf,表明修改差值。正向流是提高后面的值,反向流是降低前面的值。而且得加堆优化迪杰斯特拉,否则跑不过去了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> PII;
const int N = 3010;
const ll inf = 100000000000010;
struct edge {
    int nxt, to;
    ll f, c;
} e[N * 20];
int inq[N], a[N], b[N], head[N], pree[N], pprev[N];
ll dis[N];
priority_queue<PII, vector<PII>, greater<PII> > q;
int n, source, sink, cnt = 1;
inline void link(int u, int v, ll f, ll c)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
    e[cnt].f = f;
    e[cnt].c = c;
}
inline void insert(int u, int v, ll f, ll c)
{
    link(u, v, f, c);
    link(v, u, 0, -c);
}
inline bool spfa()
{
    int l = 1, r = 0;
    for(int i = source; i <= sink; ++i)
        dis[i] = inf;
    dis[source] = 0;
    q.push(make_pair(0, source));
    while(!q.empty())
    {
        PII x = q.top();
        q.pop();
        int u = x.second;
        if(dis[u] != x.first) continue;
        for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && dis[e[i].to] > dis[u] + e[i].c)
        {
            pree[e[i].to] = i;
            pprev[e[i].to] = u;
            dis[e[i].to] = dis[u] + e[i].c;
            q.push(make_pair(dis[e[i].to], e[i].to));
        }
    }
    return dis[sink] != inf;
}
inline ll getflow()
{
    int now = sink;
    ll delta = inf;
    while(now != source)
    {
        delta = min(delta, e[pree[now]].f);
        now = pprev[now];
    }
    now = sink;
    while(now != source)
    {
        e[pree[now]].f -= delta;
        e[pree[now] ^ 1].f += delta;
        now = pprev[now];
    }
    return delta * dis[sink];
}
inline ll mcmf()
{
    ll ret = 0;
    while(spfa()) ret += getflow();
    return ret;
}
int main()
{
    scanf("%d", &n);
    source = 0;
    sink = n + 2;
    for(int i = 1; i <= n; ++i) 
        scanf("%d", &a[i]);
    for(int i = 2; i <= n; ++i)
    {
        b[i] = a[i] - a[i - 1];
        if(b[i] > 0) insert(i, sink, b[i] - 1, 0);
        else insert(source, i, -b[i] + 1, 0);
    }
    for(int i = 1; i <= n; ++i) 
    {
        insert(i, i + 1, inf, 1);
        insert(i + 1, i, inf, 1);
    }
    insert(1, sink, inf, 0);
    insert(n + 1, sink, inf, 0);
    printf("%lld\n", mcmf());
    return 0;
}
View Code

 

posted @ 2017-07-12 22:06  19992147  阅读(155)  评论(0编辑  收藏  举报