bzoj3532

题意:
给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若
干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。 如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
1 < =N < =700
T < =5

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#define N 1500
#define LL long long
using namespace std;
struct node{int y,nex;LL c;}a[N*N];
struct node1{int d,id;}C[N];
int A[N],B[N],n,len,fir[N],f[N],w[N],res[N],cnt,st,ed,tail,p[N],h[N];
LL inf=1ll<<50;
bool b[N];
void ins(int x,int y,LL c)
{
    a[++len].y=y;a[len].c=c;a[len].nex=fir[x];fir[x]=len;
    a[++len].y=x;a[len].c=0;a[len].nex=fir[y];fir[y]=len;
}
bool cmp(node1 x,node1 y)
{
    if(x.d<y.d) return 1;
    return 0;
}
bool bfs()
{
    for(int i=1;i<=2*n+2;i++) h[i]=0;
    p[1]=st;h[st]=1;tail=1;
    for(int i=1;i<=tail;i++)
    {
        int x=p[i];
        for(int k=fir[x];k;k=a[k].nex)
        {
            int y=a[k].y;
            if(a[k].c && h[y]==0)
            {
                h[y]=h[x]+1;p[++tail]=y;
            }
        }
    }
    return h[ed];
}
LL dfs(int x,LL flow)
{
    LL t,dlt=0;
    if(x==ed) return flow;
    for(int k=fir[x];k;k=a[k].nex)
    {
        int y=a[k].y;
        if(dlt==flow) break;
        if(a[k].c && h[y]==h[x]+1) {t=dfs(y,min(flow-dlt,a[k].c));dlt+=t;a[k].c-=t;a[k^1].c+=t;}
    }
    if(dlt==0) h[x]=0;
    return dlt;
}
void flow_back(int x,int y,LL c)
{
    st=x;ed=y;
    while(bfs() && c) 
        c-=dfs(st,c);
}
int main()
{
    int z;scanf("%d",&z);
    while(z--)
    {
        for(int i=1;i<=2*n+2;i++) fir[i]=0;
        len=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&A[i]);
        for(int i=1;i<=n;i++) scanf("%d",&B[i]);
        for(int i=1;i<=n;i++) scanf("%d",&C[i].d),C[i].id=i;
        int mx=0;
        for(int i=n;i>=1;i--)
        {
            f[i]=0;
            for(int j=i+1;j<=n;j++) if(A[j]>A[i]) f[i]=max(f[i],f[j]);
            f[i]++;
            mx=max(mx,f[i]);
        }
        st=2*n+1;ed=st+1;
        for(int i=1;i<=n;i++) b[i]=0;
        for(int i=1;i<=n;i++) w[i]=len+1,ins(i,i+n,B[i]);
        for(int i=1;i<=n;i++)
        {
            if(f[i]==mx) b[i]=1;
            if(b[i]==0) continue;
            for(int j=i+1;j<=n;j++) if(A[j]>A[i] && f[j]==f[i]-1) b[j]=1;
        }
        for(int i=1;i<=n;i++)
        {
            if(b[i]==0) continue;
            if(f[i]==mx) ins(st,i,inf);
            if(f[i]==1) ins(i+n,ed,inf);
            for(int j=i+1;j<=n;j++) if(A[j]>A[i] && f[j]==f[i]-1) ins(i+n,j,inf);
        }
        LL mxf=0;
        while(bfs()) mxf+=dfs(st,inf);
        printf("%lld ",mxf);
        sort(C+1,C+n+1,cmp);
        cnt=0;
        for(int i=1;i<=n;i++)
        {
            int k=w[C[i].id];
            if(a[k].c) continue;
            int x=a[k^1].y,y=a[k].y;
            st=x;ed=y;
            if(bfs()) continue;
            res[++cnt]=C[i].id;
            flow_back(x,2*n+1,a[k^1].c);
            flow_back(2*n+2,y,a[k^1].c);
            a[k^1].c=0;
        }
        printf("%d\n",cnt);
        sort(res+1,res+cnt+1);
        for(int i=1;i<cnt;i++) printf("%d ",res[i]);
        printf("%d\n",res[cnt]);
    }
    return 0;
}

题解:
拆点最小割是显然的,然而字典序就不会做了QAQ
膜了题解,看到一种退流的方法
做完网络流后,贪心地尽量让c小的边成为割边
是否能做为割边就看小姿势><
选完一条边做割边后,要消除它对网络的影响,就要退还所有流过这条边的流量。
边(x,y)容量c,就
设源点为x,汇点为st,最大流
设源点为ed,汇点为y,最大流
用心感受一下,是不是很对呢?
我觉得这个最大流要加流量限制c,但题解的代码都没加,似乎是因为这个图的特殊性退还的流量一定为c?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值