zoukankan      html  css  js  c++  java
  • SDOI2014 LIS

    题目链接:戳我

    我们先做一个DP,就能求出来到前i位的最长上升子序列的长度(maxx[i]数组)。

    然后我们考虑求最小割——给每个点拆点,如果要割掉这个点,就相当于把in[i]--out[i]这条边给割掉了。

    然后如果在最长上升子序列中,该位下面可以接很多,那么就从该位代表的out向下面可以接的in连边。

    然后跑最小割就行了QAQ

    但是......之后还需要求字典序最小的最小割方案。
    那么我们先把边从小到大排个序,然后把所有可能割边都捞出来,贪心地选择。
    但是有一个问题,就是我们选择了一个边之后,它会对我们之后的决策产生影响(比如说,本来应该选的边可以不选了)
    所以我们要强行退流(具体操作可以看代码)。我们知道选了这条边之后,这条边的可替代品就不需要选了,这些可替代它的边显然是存在于S-u,v-T之间的。所以我们直接退掉他们满流边的流量就行啦!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define S 0
    #define T 2*n+1
    #define MAXN 1510
    #define INF 0x3f3f3f3f
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch==-1)f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int TT,n,t=1,cnt,kkk;
    int num[MAXN];
    int ans[MAXN],in[MAXN],out[MAXN],done[MAXN];
    int head[MAXN],cur[MAXN],dis[MAXN],dp[MAXN][MAXN],maxx[MAXN];
    struct Node{int id,a,b,c;}node[MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN*MAXN*2];
    inline void add(int from,int to,int dis)
    {
    //	printf("[%d %d] %d
    ",from,to,dis);
    	edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
    	edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,head[to]=t;
    }
    inline bool check(int s,int t)
    {
    	queue<int>q;
    	memset(done,0,sizeof(done));
    	q.push(s);done[s]=1;
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		if(u==t) return true;
    		for(int i=head[u];i;i=edge[i].nxt)
    		{
    			int v=edge[i].to;
    			if(edge[i].dis&&done[v]==0) 
    				q.push(v),done[v]=1;
    		}
    	}
    	return false;
    }
    inline bool bfs(int s,int t)
    {
    	queue<int>q;
    	memset(dis,0x3f,sizeof(dis));
    	memcpy(cur,head,sizeof(head));
    	q.push(s);dis[s]=0;
    	while(!q.empty())
    	{
    		int u=q.front(); q.pop();
    		for(int i=head[u];i;i=edge[i].nxt)
    		{
    			int v=edge[i].to;
    			if(edge[i].dis&&dis[v]==0x3f3f3f3f)
    			{
    				dis[v]=dis[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	if(dis[t]==0x3f3f3f3f) return false;
    	return true;
    }
    inline int dfs(int x,int t,int f)
    {
    	if(!f||x==t) return f;
    	int used=0,w;
    	for(int i=cur[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		cur[x]=i;
    		if(dis[v]==dis[x]+1&&(w=dfs(v,t,min(edge[i].dis,f))))
    		{
    			edge[i].dis-=w;
    			edge[i^1].dis+=w;
    			used+=w,f-=w;
    			if(!f) break;
    		}
    	}
    	return used;
    }
    inline int dinic(int s,int t)
    {
    	int cur_ans=0;
    	while(bfs(s,t)) cur_ans+=dfs(s,t,INF);
    	return cur_ans;
    }
    inline void pre()
    {
    	for(int i=1;i<=n;i++)
    	{
    		maxx[i]=1;
    		for(int j=1;j<i;j++)
    			if(node[i].a>node[j].a)
    				maxx[i]=max(maxx[i],maxx[j]+1);
    	}	
    	for(int i=1;i<=n;i++) kkk=max(kkk,maxx[i]);
    }
    inline void add_edge()
    {
    	for(int i=1;i<=n;i++) in[i]=i;
    	for(int i=n+1;i<=2*n;i++) out[i-n]=i;
    	for(int i=1;i<=n;i++) add(in[i],out[i],node[i].b),num[i]=t-1;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<i;j++)
    		{
    			if(maxx[j]+1==maxx[i]&&node[j].a<node[i].a)
    				add(out[j],in[i],INF);
    		}
    	}
    	for(int i=1;i<=n;i++) if(maxx[i]==1) add(S,in[i],INF);
    	for(int i=1;i<=n;i++) if(maxx[i]==kkk) add(out[i],T,INF);
    }
    inline bool cmp(struct Node x,struct Node y){return x.c<y.c;}
    inline void solve()
    {
    	for(int i=1;i<=n;i++)
    	{
    		int x=node[i].id;
    		if(check(in[x],out[x])) continue;
    		ans[++cnt]=x;
    		while(bfs(T,out[x])) dfs(T,out[x],INF);
    		while(bfs(in[x],S)) dfs(in[x],S,INF);
    		edge[num[x]].dis=0,edge[num[x]^1].dis=0;
    	}
    }
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	TT=read();
    	while(TT--)
    	{
    		memset(head,0,sizeof(head));
    		cnt=0,kkk=0;
    		t=1;
    		n=read();
    		for(int i=1;i<=n;i++) node[i].a=read();
    		for(int i=1;i<=n;i++) node[i].b=read();
    		for(int i=1;i<=n;i++) node[i].c=read();
    		pre();
    		add_edge();
    		printf("%d ",dinic(S,T));
    		for(int i=1;i<=n;i++) node[i].id=i;
    		sort(&node[1],&node[n+1],cmp);
    		solve();
    		printf("%d
    ",cnt);
    		sort(&ans[1],&ans[cnt+1]);
    		for(int i=1;i<=cnt;i++) printf("%d ",ans[i]); puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    IE 下 telerik RadAjaxManager 多次请求,LoadingPanel 点击消失
    Razor 越来越像 Rails 了
    MongoDB 初学
    Virtual PC 2007 SP1 中,Windows Server 2008 SP2 下安装 SQL Server 2008 R2
    VB 程序员:不要放松对自己的要求
    Linq to SQL bug: Char(1) maps to System.Char
    Linq to SQL: System.InvalidCastException: Specified cast is not valid
    ASP.NET 4: 允许对URL中的特殊字符串放宽要求
    IE 8 打开新 Tab 页报错 window.external.BuildNewTabPage()
    过完年了
  • 原文地址:https://www.cnblogs.com/fengxunling/p/11005895.html
Copyright © 2011-2022 走看看