• 【BZOJ-3532】Lis 最小割 + 退流


    3532: [Sdoi2014]Lis

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 704  Solved: 264
    [Submit][Status][Discuss]

    Description

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

    Input

      输入包含多组数据。
        输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
        每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。

    Output

        对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在4中的的位置,按升序输出。

    Sample Input

    1
    6
    3 4 4 2 2 3
    2 1 1 1 1 2
    6 5 4 3 2 1

    Sample Output

    4 3
    2 3 6
    解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但{A2,43,A6)对应的C值的字典序最小。

    HINT

    1 < =N < =700     T < =5

    Source

    Round 1 Day 2

    Solution

    最小割的模型还是很显然的,先dp一边,然后转移之间连边,源点到初始状态,最终状态到汇点,拆点限制流量,最小割即删去的代价。

    然后考虑字典序最小的割,可以通过按字典序枚举每条限流边,如果这条边满流且无法再流过去,则这条割边可选,然后消除它的影响,继续处理。

    消除影响可以利用退流的思想,其实就是将这条边<u,v>正反置0,然后跑一遍T->v,一遍u->S即可。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    inline int read()
    {
    	int x=0,f=1; 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;
    }
    
    #define MAXN 5010
    int N,cas,a[MAXN],b[MAXN],c[MAXN];
    
    struct EdgeNode{
    	int next,to,cap;
    }edge[2000100];
    int head[MAXN],cnt=1;
    inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
    inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,0);}
    
    int h[MAXN],cur[MAXN],S,T;
    queue<int>q;
    inline bool bfs(int s,int t)
    {
    	for (int i=S; i<=T; i++) h[i]=-1;
    	q.push(s); h[s]=0;
    	while (!q.empty()) {
    		int now=q.front(); q.pop();
    		for (int i=head[now]; i; i=edge[i].next) 
    			if (edge[i].cap && h[edge[i].to]==-1)
    				h[edge[i].to]=h[now]+1,q.push(edge[i].to);
    	}
    	return h[t]!=-1;
    }
    
    inline int dfs(int now,int low,int s,int t)
    {
    	if (now==t) return low;
    	int w,used=0;
    	for (int i=cur[now]; i; i=edge[i].next) 
    		if (edge[i].cap && h[edge[i].to]==h[now]+1) {
    			int w=dfs(edge[i].to,min(low-used,edge[i].cap),s,t);
    			edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
    			if (used==low) return used;
    			if (edge[i].cap) cur[now]=i;
    		}
    	if (!used) h[now]=-1;
    	return used;
    }
    
    #define INF 0x7fffffff
    inline int Dinic(int s,int t)
    {
    	int re=0;
    	while (bfs(s,t)) {
    		for (int i=S; i<=T; i++) cur[i]=head[i];
    		re+=dfs(s,INF,s,t);
    	}
    	return re;
    }
    
    #define Pa pair<int,int>
    #define MP make_pair
    #define Id first
    #define ps second
    
    inline bool cmp(Pa x,Pa y) {return c[x.Id]<c[y.Id];}
    
    int stack[MAXN],top=0;
    int main()
    {
    	cas=read();
    	while (cas--) {
    		cnt=1;
    		memset(head,0,sizeof(head));
    		
    		N=read();
    		for (int i=1; i<=N; i++) a[i]=read();
    		for (int i=1; i<=N; i++) b[i]=read();
    		for (int i=1; i<=N; i++) c[i]=read();
    		
    		static int f[MAXN];
    		
    		for (int i=1; i<=N; i++) f[i]=1;
    		
    		for (int i=1; i<=N; i++)
    			for (int j=0; j<i; j++)
    				if (a[i]>a[j]) f[i]=max(f[i],f[j]+1);
    		
    		int mx=0;
    		for (int i=1; i<=N; i++) mx=max(mx,f[i]);
    		
    		S=0,T=2*N+1;
    		
    		static Pa id[MAXN];
    		
    		for (int i=1; i<=N; i++) {
    			if (f[i]==1) InsertEdge(S,i,INF);
    			if (f[i]==mx) InsertEdge(i+N,T,INF);
    			InsertEdge(i,i+N,b[i]); id[i]=MP(i,cnt);
    			for (int j=1; j<i; j++)
    				if (f[i]-1==f[j] && a[i]>a[j]) InsertEdge(j+N,i,INF);
    		}
    		
    		int ans=Dinic(S,T);
    		
    		stable_sort(id+1,id+N+1,cmp);
    		
    		top=0;
    		for (int i=1; i<=N; i++) {
    			int e1=id[i].ps^1,e2=id[i].ps,p1=id[i].Id,p2=p1+N;
    			if (!edge[e1].cap && !bfs(p1,p2)) {
    				Dinic(p1,S); Dinic(T,p2);
    				edge[e1].cap=edge[e2].cap=0;
    				stack[++top]=id[i].Id;
    			}
    		}
    		
    		stable_sort(stack+1,stack+top+1);
    
    		printf("%d %d
    ",ans,top);
    		for (int i=1; i<top; i++) printf("%d ",stack[i]); printf("%d
    ",stack[top]);
    		
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Premiere Pro 2020 教程(二)
    程序员的10个好习惯(转自四猿外)
    HtmlAgilityPack 抓取页面的乱码处理
    【Python爬虫】 学习笔记 ajax下爬取豆瓣请求第一页
    【Python爬虫】 学习笔记 get请求的方法
    【Python爬虫】 学习笔记 post请求的方法
    【Python爬虫】 学习笔记 post请求的方法(Cookie反爬)
    jQuery选择器实例手册
    弹出模态窗口并传递数值
    java synchronized详解
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6540807.html
Copyright © 2020-2023  润新知