• bzoj 3532


    很好的一道题,对理解最小割有很大帮助

    首先,不难发现本题与网络流24题中的某一道很类似,我们可以先跑一次dp求出每个节点的LIS,然后拆点,拆出的两点之间连流量为删除的代价的边,剩下的点之间按dp的转移连流量正无穷的边,最后跑最小割即为第一问答案

    但是第二问有个问题:又引入了一个量要求最小割字典序最小,这怎么办?

    首先我们考虑:字典序最小的话我们就要让第一个尽可能小,然后让第二个尽可能小...以此类推

    那么我们考虑什么样的边可能在最小割中

    这样的边一定满足如下条件:

    第一.这条边已经满流了

    第二.这条边的两端之间不存在增广路

    如果一条边满足这样的条件,那么这条边就可以在一个最小割之中

    那么我们把点按第三个变量排序,从小到大判断能否加入最小割,如果能加入最小割的话则需要退流,也就是退掉源点和汇点到这条边两端的流,这一步可以反向dfs解决

    于是这题就结束了

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    const int inf=0x3f3f3f3f;
    struct Edge
    {
        int nxt;
        int to;
        int val;
        int flo;
    }edge[500005];
    struct Info
    {
        int num,v,w,c;
        friend bool operator < (Info a,Info b)
        {
            return a.c<b.c;
        }
    }f[1005];
    int re[1005];
    int head[5005];
    int cur[5005];
    int dis[5005];
    int toe[5005];
    int dp[1005];
    int cnt=1,ttop=0;
    int T,n;
    int st,ed;
    void init()
    {
        memset(head,0,sizeof(head));
        memset(dp,0,sizeof(dp));
        cnt=1,ttop=0;
    }
    void add(int l,int r,int w)
    {
        edge[cnt].nxt=head[l];
        edge[cnt].to=r;
        edge[cnt].val=w;
        head[l]=cnt++;
    }
    void dadd(int l,int r,int w)
    {
        add(l,r,w),add(r,l,0);
    }
    int ide(int x)
    {
        return x&1?x+1:x-1;
    }
    bool bfs(int fr,int Ed)
    {
        memcpy(cur,head,sizeof(head));
        memset(dis,0,sizeof(dis));
        dis[fr]=1;
        queue <int> M;
        M.push(fr);
        while(!M.empty())
        {
            int u=M.front();
            M.pop();
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int to=edge[i].to;
                if(edge[i].val>edge[i].flo&&!dis[to])
                {
                    dis[to]=dis[u]+1,M.push(to);
                    if(to==Ed)return 1;
                }
            }
        }
        return dis[Ed];
    }
    int dfs(int x,int lim,int Ed)
    {
        if(x==Ed||!lim)return lim;
        int ret=0;
        for(int i=cur[x];i;i=edge[i].nxt)
        {
            cur[x]=i;
            int to=edge[i].to;
            if(dis[to]==dis[x]+1&&edge[i].val>edge[i].flo)
            {
                int temp=dfs(to,min(lim,edge[i].val-edge[i].flo),Ed);
                if(temp)
                {
                    ret+=temp,lim-=temp;
                    edge[i].flo+=temp,edge[ide(i)].flo-=temp;
                    if(!lim)break;
                }
            }
        }
        return ret;
    }
    int dinic()
    {
        int ans=0;
        while(bfs(st,ed))ans+=dfs(st,inf,ed);
        return ans;
    }
    inline int read()
    {
        int f=1,x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int main()
    {
        T=read();
        while(T--)
        {
            init();
            n=read();
            st=2*n+1,ed=2*n+2;
            for(int i=1;i<=n;i++)f[i].num=i,f[i].v=read(),dp[i]=1;
            for(int i=1;i<=n;i++)f[i].w=read(),dadd((i<<1)-1,i<<1,f[i].w),toe[i]=cnt-1;
            for(int i=1;i<=n;i++)for(int j=1;j<i;j++)if(f[i].v>f[j].v)dp[i]=max(dp[i],dp[j]+1);
            int maxx=0;
            for(int i=1;i<=n;i++)maxx=max(maxx,dp[i]);
            for(int i=1;i<=n;i++)
            {
                if(dp[i]==1)dadd(st,(i<<1)-1,inf);
                else if(dp[i]==maxx)dadd(i<<1,ed,inf);
                for(int j=1;j<i;j++)if(f[i].v>f[j].v&&dp[j]+1==dp[i])dadd(j<<1,(i<<1)-1,inf);
            }
            for(int i=1;i<=n;i++)f[i].c=read();
            printf("%d ",dinic());
            sort(f+1,f+n+1);
            for(int i=1;i<=n;i++)
            {
                int k=f[i].num;
                if(bfs((k<<1)-1,k<<1))continue;
                re[++ttop]=k;
                while(bfs(ed,(k<<1)))dfs(ed,inf,(k<<1));
                while(bfs((k<<1)-1,st))dfs((k<<1)-1,inf,st);
                edge[toe[k]].val=edge[ide(toe[k])].val=0;
                edge[toe[k]].flo=edge[ide(toe[k])].flo=0;
            }
            printf("%d
    ",ttop);
            sort(re+1,re+ttop+1);
            for(int i=1;i<=ttop;i++)printf("%d ",re[i]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    Plahte
    Sound 静音问题
    【模板】线段树 2
    winform GDI基础(四)简单截屏
    winform GDI基础(二)画带圆角的矩形框
    winform GDI基础(三)实现画笔
    winform GDI基础(一)
    winform播放视频(windows media player)
    c# 锁的使用
    C#Task学习
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11170117.html
Copyright © 2020-2023  润新知