博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj千题计划141:bzoj3532: [Sdoi2014]Lis
阅读量:4326 次
发布时间:2019-06-06

本文共 3451 字,大约阅读时间需要 11 分钟。

 

如果没有字典序的限制,那么DP拆点最小割即可

 

加上字典序的限制:

按c从小到大枚举最小割边集中的边,去掉这条边对网络的影响,继续枚举直至获得最小割边集

 

判断是不是最小割边集中的边:

在残量网络中边的起点和终点不连通

注:最小割边集中的边一定满流,但满流边不一定是最小割边集中的边

如下图所示,流量为1和3的两条边满流,但最小割边集为流量为4的那条边

 

去掉一条边对网络的影响:

边:u-->v

这条边的流量和反向弧的流量置为0

在残量网络上,汇点向v跑一遍最大流,u向源点跑一遍最大流

 

判断已经得到了最小割中的所有边:

残量网络上,源点和汇点不连通

 

#include
#include
#include
#include
#include
using namespace std; #define N 1410#define M 520000const int inf=2e9; int n;int a[N],b[N],c[N];int f[N]; int tot;int front[N],nxt[M<<1],to[M<<1],val[M<<1],from[M<<1];int lev[N],num[N];int path[N];int cur[N]; int src,decc;int id[N];bool use[N];int cnt[N];int all;int ans[N];bool vis[N];void read(int &x){ x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }}void add(int u,int v,int w){ to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0; // cout<
<<' '<
<<' '<
<<'\n';}bool bfs(){ queue
q; for(int i=1;i<=all;++i) lev[i]=all; q.push(decc); lev[decc]=0; int now,t; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) { t=to[i]; if(lev[t]==all && val[i^1]) { lev[t]=lev[now]+1; q.push(t); } } } return lev[src]!=all;} int augment(){ int now=decc,flow=inf; int i; while(now!=src) { i=path[now]; flow=min(flow,val[i]); now=from[i]; } now=decc; while(now!=src) { i=path[now]; val[i]-=flow; val[i^1]+=flow; now=from[i]; } return flow;} void isap(){ int flow=0; if(!bfs()) return ; memset(num,0,sizeof(num)); for(int i=1;i<=all;++i) num[lev[i]]++,cur[i]=front[i]; int now=src,t; while(lev[src]
a[i]) mx=max(mx,f[j]); f[i]=mx+1; max_len=max(max_len,f[i]); } tot=1; memset(front,0,sizeof(front)); for(int i=1;i<=n;++i) { id[i]=tot+1; add(i<<1,i<<1|1,b[i]); } for(int i=1;i<=n;++i) if(f[i]==max_len) add(src,i<<1,inf); for(int i=1;i<=n;++i) if(f[i]==1) add(i<<1|1,decc,inf); for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) if(a[j]>a[i] && f[i]==f[j]+1) add(i<<1|1,j<<1,inf);}bool find(int u,int v){ memset(vis,false,sizeof(vis)); queue
q; q.push(u); vis[u]=true; int now,t; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) { if(!val[i]) continue; t=to[i]; if(!vis[t]) { vis[t]=true; q.push(t); } } } return vis[v];}void solve(){ int sum=0,num=0; int mi; c[0]=inf; memset(use,false,sizeof(use)); while(1) { mi=0; for(int i=1;i<=n;++i) if(!val[id[i]] && !use[i] && c[mi]>c[i]) mi=i; use[mi]=true; if(find(from[id[mi]],to[id[mi]])) continue; ans[++num]=mi; sum+=b[mi]; val[id[mi]]=val[id[mi]+1]=0; src=all; decc=mi<<1|1; isap(); src=mi<<1; decc=1; isap(); src=all; decc=1; if(!bfs()) break; } cout<
<<' '<
<<'\n'; sort(ans+1,ans+num+1); for(int i=1;i

 

3532: [Sdoi2014]Lis

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 977  Solved: 362
[][][]

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

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8044826.html

你可能感兴趣的文章
技术分析淘宝的超卖宝贝
查看>>
i++和++1
查看>>
react.js
查看>>
P1313 计算系数
查看>>
NSString的长度比较方法(一)
查看>>
Azure云服务托管恶意软件
查看>>
My安卓知识6--关于把项目从androidstudio工程转成eclipse工程并导成jar包
查看>>
旧的起点(开园说明)
查看>>
生产订单“生产线别”带入生产入库单
查看>>
crontab导致磁盘空间满问题的解决
查看>>
java基础 第十一章(多态、抽象类、接口、包装类、String)
查看>>
Hadoop 服务器配置的副本数量 管不了客户端
查看>>
欧建新之死
查看>>
自定义滚动条
查看>>
APP开发手记01(app与web的困惑)
查看>>
笛卡尔遗传规划Cartesian Genetic Programming (CGP)简单理解(1)
查看>>
mysql 日期时间运算函数(转)
查看>>
初识前端作业1
查看>>
ffmpeg格式转换命令
查看>>
万方数据知识平台 TFHpple +Xpath解析
查看>>