1. 程式人生 > 實用技巧 >小Y寫文章 必須匹配和不必須匹配的網路流

小Y寫文章 必須匹配和不必須匹配的網路流

題目

https://ac.nowcoder.com/acm/problem/15600

題目描述

小Y寫了一篇文章,他對自己的文筆很有自信,尤其是自己總結出了一套計算文章通順性的公式。
文章共N段,對於文章的每一段小Y對它都能計算出一個估值A_i,而一篇文章的不連貫值定義為\(\max\{|A_i-A_{i-1}|, 2\leq i\leq n\}max{∣A_{i} −A _{i−1}∣,2≤i≤n}\),現在小Y想要釋出他的文章,但是編輯小Z讓他加入一些廣告,具體來說就是M段估值分別為$B_i的新段落。小Y很頭疼,想讓修改後的文章依然通順,也就是要最小化不連貫值,已知小Y加入新段落的時候不需要考慮新段落之間的順序,但是隻可以在原文章的開頭段之前、結尾段之後、或兩段之間加入一段新段落,每個位置只能加入最多一段。請幫助焦頭爛額的小Y求出將這M個新段落全都加入之後的最小不連貫值。

輸入描述:

多組資料,第一行有一個正整數\(T(T≤30)\)表示資料組數。
之後有T組資料,每組資料第一行有兩個整數\(N,M(1≤N≤200,1≤M≤N+1)。\)
接著有兩行,其中第一行有N個正整數\(A_i\),表示原文章按順序每段的估值。
第二行有M個正整數\(B_i\),表示新段落每段的估值。\((1 \leq A_i, B_i \leq10^9)\)
輸出描述:
對於每組資料,輸出一個整數表示求出的最小不連貫值。

示例1

輸入
2
4 3
1 6 5 2
3 1 4
4 2
1 2 4 3
10 10
輸出
3
7

說明

第一組樣例方案可以是 (1) 1 (4) 6 5 (3) 2
第二組樣例方案可以是 1 2 4 (10) 3 (10)

思路

最小,我們考慮二分判斷滿足。
有n+1個空,有m個元素。那麼就是n個節點和m個節點匹配。
但是有的空是必須匹配。如果a[i+1]-a[i]>mid,那麼這個空就必須填。
有的空是可以點。如果a[i+1]-a[i]<=mid,那麼這個空就可填看不填。
怎麼保證這個必須填的一定填
1:設定一個必須填的次源點,一個可以填的次源點。流相應的流量。那麼要滿流一點要流滿必須流的流量
2:有上下限的網路流
3:費用流,把必須流的節點費用設定1.其他設定為2。
這裡我們用了第1個解決方法。

#pragma GCC optimize(3, "Ofast", "inline")
#include<bits/stdc++.h>
#define pii pair<int, int>
#define INF 1000000007
using namespace std;
using namespace std;
const int maxn =500+10;

struct Edge {
    int from,to,cap,flow;
    Edge() {}
    Edge(int f,int t,int c,int fl):from(f),to(t),cap(c),flow(fl) {}
};
struct Dinic {
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int cur[maxn];
    int d[maxn];
    bool vis[maxn];

    void init(int n,int s,int t) {
        this->n=n, this->s=s, this->t=t;
        edges.clear();
        for(int i=0; i<n; i++)
            G[i].clear();
    }

    void AddEdge(int from,int to,int cap) {
        //cout<<from<<" "<<to<<"="<<cap<<endl;
        edges.push_back( Edge(from,to,cap,0) );
        edges.push_back( Edge(to,from,0,0) );
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS() {
        queue<int> Q;
        Q.push(s);
        memset(vis,0,sizeof(vis));
        d[s]=0;
        vis[s]=true;
        while(!Q.empty()) {
            int x=Q.front();
            Q.pop();
            for(int i=0; i<G[x].size(); ++i) {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to] && e.cap>e.flow) {
                    d[e.to]=1+d[x];
                    vis[e.to]=true;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a) {
        if(x==t || a==0)
            return a;
        int flow=0,f;
        for(int& i=cur[x]; i<G[x].size(); ++i) {
            Edge& e=edges[G[x][i]];
            if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) {
                e.flow +=f;
                edges[G[x][i]^1].flow -=f;
                flow +=f;
                a-=f;
                if(a==0)
                    break;
            }
        }
        return flow;
    }

    int max_flow() {
        int ans=0;
        while(BFS()) {
            memset(cur,0,sizeof(cur));
            ans += DFS(s,INF);
        }
        return ans;
    }
} DC;


int a[205], b[205];
int n, m;
int ok(int x) {
    //cout<<"-----"<<x<<"-----"<<endl;
    int S=0, T=500, S1=T-1, S2=T-2;
    DC.init(505, S, T);
    int cut=0;


    DC.AddEdge(S2, 1, 1), DC.AddEdge(S2, n+1, 1);//可以放
    for(int i=1; i<n; i++){
        if(abs(a[i+1]-a[i])>x){//必須放
            cut++; DC.AddEdge(S1, i+1, 1);
        }
        else{
            DC.AddEdge(S2, i+1, 1);
        }
    }
    DC.AddEdge(S, S1, cut); DC.AddEdge(S, S2, m-cut);

    for(int i=0; i<=n; i++) {
        for(int k=1; k<=m; k++) {
            if(i==0) {
                if(abs(a[i+1]-b[k])<=x) {
                    DC.AddEdge(i+1, n+1+k, 1);
                }
            } else if(i==n) {
                if(abs(a[i]-b[k])<=x){
                    DC.AddEdge(i+1, n+1+k, 1);
                }
            } else {
                if(abs(a[i]-b[k])<=x&&abs(a[i+1]-b[k])<=x){
                    DC.AddEdge(i+1, n+1+k, 1);
                }
            }
        }
    }
    for(int i=1; i<=m; i++){
        DC.AddEdge(n+1+i, 500, 1);
    }
    int ans=DC.max_flow();
    //cout<<x<<"="<<ans<<endl;
    return ans==m;
}

int main() {

    int t;scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        int mi=1<<30, mx=0;
        for(int i=1; i<=n; i++) {
            scanf("%d", &a[i]);
            mi=min(mi, a[i]);
            mx=max(mx, a[i]);
        }
        for(int i=1; i<=m; i++) {
            scanf("%d", &b[i]);
            mi=min(mi, b[i]);
            mx=max(mx, b[i]);
        }
        int l=0, r=mx-mi, k=0;
        while(l<=r) {
            int mid=l+r>>1;
            if(ok(mid)) {
                r=mid-1;
                k=mid;
            } else {
                l=mid+1;
            }
        }
        printf("%d\n", k);
    }

    return 0;
}