网络流中的一种套路

近期竟然碰到了多次这种类型的题目,而且还变着法,还是总结一下为妙。

焦作F Modular Production Line

CodeForces 164C Machine Programming

POJ 3680 Intervals

以上三道题应该说是同一道题,建图方法都是焦作F那种。

$S$向1连容量为$k$的边以后,$l$向$r$连容量为1,费用为$-c$的边,然后$i$向$i+1(如果i > n,连向T)$连容量为$k$,费用为0的边。只有上界,无下界,就是你最多选$k$个,最少选0个。

Gym 101190D Delight for a Cat

这个题转换的好呀。竟然能转换成上面那种做题套路。

网上这道题题解好多,两个写的好的,链接 1    2

就是和上面不同的是 $i$向$i+1$连的边既有上界,又有下界。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1100;
const ll INF = 1e18;
ll dist[maxn];
int pv[maxn],pe[maxn];
struct edge
{
    int to, cap, pre;
    int cost;
}e[7000];
int tot = 0, head[maxn];
void init(int n)
{
    tot = 0;
    fill(head, head + n + 1, -1);
}
void add(int from,int to,int cap, int cost)
{
    e[tot].pre = head[from];
    e[tot].to = to;
    e[tot].cap = cap;
    e[tot].cost = cost;
    head[from] = tot++;
}
void addedge(int from,int to,int cap, int cost)
{
    add(from,to,cap,cost);
    add(to,from,0,-cost);
}
int vis[maxn];
void SPFA(int s, int t)
{
    for(int i = 1; i < maxn; i++) dist[i] = INF;
    memset(vis, 0, sizeof(vis));
    dist[s] = 0, vis[s] = 1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = e[i].pre)
        {

            int to = e[i].to, cap = e[i].cap;
            if(cap > 0 && (dist[to] - (dist[u] + e[i].cost)) > 0)
            {
                pv[to] = u, pe[to] = i;
                dist[to] = dist[u] + e[i].cost;
               // printf("%d %d %d %lld\n",u, to, cap, dist[to]);
                if(!vis[to])
                {
                    vis[to] = 1;
                    q.push(to);
                }
            }
        }
        //system("pause");
    }
}
ll min_cost_flow(int s,int t,int f,int& max_flow)
{
    ll ret = 0;
    while(f>0)
    {
        SPFA(s, t);
        if(dist[t] == INF) return ret;///同一目的地,每次增广路都是最小费用
        ///当所有边的流量都流净后,即没有残余网络,返回。
        int d = f;
        for(int v=t;v!=s;v=pv[v])
        {
            d = min(d, e[pe[v]].cap);
        }
        f -= d;
        max_flow += d;
        ret += (ll)d*dist[t]; ///走一单位就消耗dist[t]
        for(int v=t;v!=s;v=pv[v])
        {
            e[pe[v]].cap -= d;
            e[pe[v]^1].cap += d;
        }
    }
    return ret;
}
int ss[maxn], ee[maxn];

int main()
{
    freopen("delight.in", "r", stdin);
    freopen("delight.out", "w", stdout);
    int n, k, ms, me; scanf("%d %d %d %d", &n, &k, &ms, &me);
    int S0 = n + 1, S = S0 + 1, T = S + 1;
    int mine = me, maxe = k - ms;
    init(n + 3);
    ll sum = 0;
    for(int i = 1; i <= n; i++) scanf("%d", &ss[i]), sum += ss[i];
    for(int i = 1; i <= n; i++) scanf("%d", &ee[i]), ee[i] -= ss[i];
    for(int i = 1; i <= n; i++)
    {
        if(i + k <= n) addedge(i, i + k, 1, -ee[i]);
        else addedge(i, T, 1, -ee[i]);
    }
    for(int i = 1; i <= n; i++)
    {
        if(i < n) addedge(i, i + 1, maxe - mine, 0);
        else addedge(i, T, maxe - mine, 0);
    }
    addedge(S, S0, maxe, 0);
    for(int i = 1; i <= k; i++)
    {
        addedge(S0, i, 1e9, 0);
    }
    int maxflow = 0;
    sum -= min_cost_flow(S, T, 1e9, maxflow);
    printf("%lld\n", sum);
    for(int i = 0; i < 2 * n; i += 2)
    {
        if(e[i].cap == 0) printf("E");
        else printf("S");
    }
    printf("\n");
    return 0;
}
Code

 

posted @ 2018-10-23 15:41  汪汪鱼  阅读(247)  评论(1编辑  收藏  举报