【网络流24题】最长递增子序列 | 一种奇怪的拆点建图方式

题目大意:

给出一段序列,让你求出:

1.最长上升子序列的长度

2.这个序列的最长上升子序列有多少个

3.如果最后一个元素和第一个元素可以用无数次,最长上升子序列有多少个

题目思路:

发现我的建图方式和网上的基本不一致 | 大概是弱者的建图方式

首先一个非常的基础的操作就是把最长上升子序列的建图给还原出来

1.首先预处理dp_i代表以i结尾的最长上升子序列的长度

2.从末状态是最长的开始,使用一个队列进行还原建图

建图完成以后,就需要考虑网络流的建图

首先遵循基本得二分图建模:

1.把一个点拆点 —— 拆成入度与出度

2.将源点连向所有的满足在最长子序列中并且dp[i] == 1的点,流量为1

3.将所有满足在最长子序列中并且dp[i]==maxl的点,流量为1

4.将每个点的出度点与入度点连边,流量为一 | 这个实质其实是每个点只能使用一次

对于第一个元素和最后一个元素可以使用多次的修改

1.只需要把1和n的出度点与入度点流量改为n——最多被n个点使用。

2.源点到1 与 n到汇点的流量改为n —— 需要给他这么多才可以

之后,就是最大流了。

需要注意既然已经把点拆点了,那就注意一下细节 a - > b的话,a即为出度,b即为入度

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pp;
const ll INF=1e17;
const int Maxn=1e6+10;
const int maxn =1e4+10;
const int mod= 1e9+7;
const int Mod = 1e6+7;
const int S = 1000;
inline bool read(ll &num)
ll n,m,p;
struct Dinic{
    ll cnt = 2;
    struct Edge{
    int e,next;
    ll w;
    };
    int _S,_T,N;
    int head[maxn],d[maxn],cur[maxn];
    Edge edge[maxn];
    void _inint(int s,int t,int n){///n包括S与T
        memset(head,0,sizeof(head));
        cnt = 2;
        _S = s,_T = t,N = n;
    }
    void addedge(int u,int v,ll w){
        edge[cnt] = Edge{v,head[u],w};
        head[u] = cnt++;
    }
    void Add(int u,int v,ll w){addedge(u,v,w);addedge(v,u,0);}
    bool bfs(){
        for(int k=0;k<=N;k++) d[k] = 0;
        queueq;q.push(_S);d[_S] = 1;
        while(!q.empty()){
            int u = q.front();q.pop();
            for(int i=head[u];i;i=edge[i].next){
                int e = edge[i].e;
                if(edge[i].w <= 0||d[e]) continue;
                d[e] = d[u]+1;
                q.push(e);
            }
        }
        for(int k=0;k<=N;k++) cur[k] = head[k];
        return (d[_T] != 0);
    }
    ll dfs(int u,ll flow){
        if(u == _T)return flow;///找到可行流
        for(int &i=cur[u];i;i=edge[i].next){
            int e = edge[i].e;
            if(d[e]!=d[u]+1||edge[i].w<=0) continue;
            ll temp = dfs(e,min(flow,edge[i].w));
            if(temp<=0) continue;
            edge[i].w -= temp;
            edge[i^1].w += temp;
            return temp;
        }
        return 0;
    }
    ll MaxFlow(){
        ll maxflow = 0,delta = 0;
        while(bfs()){
            while(delta = dfs(_S,INF)) maxflow+= delta;
        }return maxflow;
    }
}g;
ll dp[maxn],a[maxn];
ll maxl = 0;
int vis[maxn];
void TraceBack(int f){
    queueq;
    memset(vis,0,sizeof(vis));
    dp[n+1] = maxl+1;
    a[n+1] = INF;
    q.push(n+1);
    while(!q.empty()){

        int u = q.front();q.pop();
        for(int i=0;i

 

你可能感兴趣的:(网络流24题,网络流)