bzoj 3532: [Sdoi2014]Lis 构造字典序最小割
来源:互联网 发布:航空数据查询接口 编辑:程序博客网 时间:2024/06/06 12:48
题意
给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。
1 < =N < =700 T < =5,Ai,Bi,Ci<=10^9
分析
如果没有字典序的限制的话,我们可以对在最长上升子序列中的元素进行拆点最小割就可以求出最小代价。
但现在的问题是如何求字典序最小的最小割。
我们可以按照Ci从小到大来枚举边。一条边u->v为割边当且仅当这条边满流并且没有从u到v的增广路,也就是不能回流。如果是割边的话我们就把这条边加入答案,然后把这条边的影响去掉。这里用的是退流算法,对t->v和u->s分别跑一次最大流就好了。
一开始dinic没加当前弧优化,然后超时了。。。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int N=705;const int inf=0x7fffffff;int n,m,s,t,cnt,last[N*2],f[N],a[N],b[N],c[N],dis[N*2],Ans[N],ans,bel[N],cur[N*2];struct edge{int to,c,next;bool use;}e[N*N*2];bool vis[N];queue<int> que;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;}void clear(){ memset(last,0,sizeof(last)); memset(bel,0,sizeof(bel)); cnt=1;ans=0;}void addedge(int u,int v,int c){ e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;e[cnt].use=0; e[++cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt;e[cnt].use=0;}void build(){ int mx=0; for (int i=1;i<=n;i++) { f[i]=1; for (int j=1;j<i;j++) if (a[j]<a[i]&&f[j]+1>f[i]) f[i]=f[j]+1; mx=max(mx,f[i]); } s=0;t=n*2+1; memset(vis,0,sizeof(vis)); for (int i=1;i<=n;i++) if (f[i]==mx) que.push(i),addedge(i+n,t,inf),vis[i]=1; while (!que.empty()) { int u=que.front();que.pop(); addedge(u,u+n,b[u]);bel[u]=cnt^1; if (f[u]==1) addedge(s,u,inf); for (int i=1;i<u;i++) if (a[i]<a[u]&&f[i]+1==f[u]) { addedge(i+n,u,inf); if (!vis[i]) vis[i]=1,que.push(i); } }}bool bfs(int s,int t){ for (int i=0;i<=n*2+1;i++) dis[i]=0; while (!que.empty()) que.pop(); dis[s]=1;que.push(s); while (!que.empty()) { int u=que.front();que.pop(); for (int i=last[u];i;i=e[i].next) if (e[i].c&&!dis[e[i].to]&&!e[i].use) { dis[e[i].to]=dis[u]+1; if (e[i].to==t) { for (int i=0;i<=n*2+1;i++) cur[i]=last[i]; return 1; } que.push(e[i].to); } } return 0;}int dfs(int x,int maxf,int t){ if (x==t||!maxf) return maxf; int ret=0; for (int &i=cur[x];i;i=e[i].next) if (e[i].c&&dis[x]+1==dis[e[i].to]&&!e[i].use) { int f=dfs(e[i].to,min(e[i].c,maxf-ret),t); e[i].c-=f; e[i^1].c+=f; ret+=f; if (maxf==ret) break; } return ret;}void dinic(){ ans=0; while (bfs(s,t)) ans+=dfs(s,inf,t); printf("%d ",ans);}void solve(){ memset(vis,0,sizeof(vis)); int tot=0; for (int i=1;i<=n;i++) { int mn=0; for (int j=1;j<=n;j++) if (!vis[j]&&(!mn||c[j]<c[mn])) mn=j; vis[mn]=1; if (!bel[mn]) continue; int u=e[bel[mn]^1].to,v=e[bel[mn]].to; if (e[bel[mn]].c||bfs(u,v)) continue; Ans[++tot]=mn; while (bfs(u,s)) dfs(u,inf,s); while (bfs(t,v)) dfs(t,inf,v); e[bel[mn]].use=e[bel[mn]^1].use=1; if (!bfs(t,s)) break; } sort(Ans+1,Ans+tot+1); printf("%d\n",tot); for (int i=1;i<tot;i++) printf("%d ",Ans[i]); printf("%d\n",Ans[tot]);}int main(){ int T=read(); while (T--) { clear(); 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(); build(); dinic(); solve(); } return 0;}
阅读全文
0 0
- bzoj 3532: [Sdoi2014]Lis 构造字典序最小割
- [BZOJ3532][Sdoi2014]Lis && 最小字典序割
- 3532: [Sdoi2014]Lis
- POJ 1815 Friendship 最小割+字典序最小割集
- POJ 1815 Friendship 最小割 + 字典序输出割点
- bzoj 2132(最小割)
- bzoj 1934(最小割)
- bzoj 3275(最小割)
- bzoj 3396(最小割)
- bzoj 2561(最小割)
- bzoj 3894(最小割)
- BZOJ 1497 最小割
- BZOJ 2039 最小割
- BZOJ 1412 最小割
- bzoj 1001 最小割
- bzoj 2561 最小割
- 【最小割】bzoj:1797最小割
- bzoj 1797 最小割【最小割】【tarjan】
- Linux之ARP协议
- 图片的轮播
- 一个长二进制串,求除3的余数
- 抽象类/接口
- java-数组
- bzoj 3532: [Sdoi2014]Lis 构造字典序最小割
- Volley传输网络数据
- Threading (C#)
- src/main/resources和WEB-INF
- Spring 申明式事务之注解
- userManager(实训)
- 统计 | 统计功效 | R语言
- java面向对象
- 文章标题