zoukankan      html  css  js  c++  java
  • 【BZOJ4200】【NOI2015】小园丁与老司机(动态规划,网络流)

    【BZOJ4200】【NOI2015】小园丁与老司机(动态规划,网络流)

    题面

    BZOJ权限题,洛谷链接

    题解

    一道二合一的题目
    考虑第一问。
    先考虑如何计算六个方向上的第一个点。
    左右上很好考虑,只需要按照(x)或者(y)轴排序就行了。
    对于(45)度的斜角,两点一定在同一条直线上。
    这条直线是(x+y=b)(x-y=b)
    所以按照(x+y)(x-y)的值分类考虑,再按照顺序在(x)轴扫一遍就可以找到了。
    考虑如何计算第一问的答案,我们发现(y)轴是单调不降的。
    所以可以以(y)来划分截断,按照(y)轴从上往下进行转移。
    (f[i])表示(i)的答案,对于所有(y)值相同的点放在一起解决。
    每次转移的时候,先将当前(y)相同的所有点通过左上右上和上三个方向进行转移。
    然后再考虑左右的转移。因为左右转移是可以先向一个方向绕过去再走回来的,
    所以考虑转移的时候需要额外注意一下。
    所以再诶外设一个(g)(f[i])表示从(i)出发不在同层内转移的最优答案。
    (g[i])表示从(i)出发,先转移到同层的某个点的最优答案。

    第二问
    先把所有可以存在于一个最优方案下的点连边。
    因为每条边都至少被覆盖一次,发现这是一个上下界网络流问题。
    因为保证有解,直接解决就好了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<set>
    #include<vector>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 50505
    #define inf 1e6
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int n;
    struct Node{int x,y,id;}p[MAX];
    bool cmpx(Node a,Node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
    bool cmpy(Node a,Node b){if(a.y!=b.y)return a.y<b.y;return a.x<b.x;}
    bool cmpn(Node a,Node b){return a.id<b.id;}
    int nt[MAX][5];
    map<int,int> M;
    int f[MAX],g1[MAX],g2[MAX],g[MAX],zy[MAX],a[MAX];
    namespace Task1
    {
        void Getdirt()
        {
            sort(&p[1],&p[n+1],cmpx);
            for(int i=1;i<n;++i)if(p[i].x==p[i+1].x)nt[p[i].id][2]=p[i+1].id;
            for(int i=1;i<=n;++i)if(p[i].x==0){nt[0][2]=p[i].id;break;}//up
            M.clear();
            for(int i=1;i<=n;++i)//left-up
            {
                int s=p[i].x+p[i].y;
                if(M[s])nt[p[i].id][3]=M[s];
                M[s]=p[i].id;
                if(s==0)nt[0][3]=p[i].id;
            }
            M.clear();
            for(int i=n;i>=1;--i)//right-up
            {
                int s=p[i].y-p[i].x;
                if(M[s])nt[p[i].id][4]=M[s];
                M[s]=p[i].id;
                if(s==0)nt[0][4]=p[i].id;
            }
        }
        int st[MAX],top;
        void Output(int x,int ans)
        {
            if(!ans)return;
            if(f[x]==ans){printf("%d ",x);Output(zy[x],ans-1);return;}
            int pos=a[x];while(pos>1&&p[pos-1].y==p[a[x]].y)--pos;
            top=0;while(p[pos].y==p[a[x]].y&&pos<=n)st[++top]=p[pos++].id;
            for(int i=1;i<=top;++i)if(st[i]==x){pos=i;break;}
            for(int i=1;i<pos;++i)
                if(f[st[i]]+top-i==g[x])
                {
                    for(int j=pos;j<=top;++j)printf("%d ",st[j]);
                    for(int j=pos-1;j>i;--j)printf("%d ",st[j]);
                    Output(st[i],f[st[i]]);
                    return;
                }
            for(int i=top;i>pos;--i)
                if(f[st[i]]+i-1==g[x])
                {
                    for(int j=pos;j>=1;--j)printf("%d ",st[j]);
                    for(int j=pos+1;j<i;++j)printf("%d ",st[j]);
                    Output(st[i],f[st[i]]);
                    return;
                }
        }
        void Solve()
        {
            Getdirt();sort(&p[1],&p[n+1],cmpy);
            for(int i=1;i<=n;++i)a[p[i].id]=i;
            for(int i=n,pos;i;i=pos)
            {
                top=0;pos=i;
                while(pos&&p[pos].y==p[i].y)st[++top]=p[pos--].id;
                reverse(&st[1],&st[top+1]);
                for(int j=1;j<=top;++j)
                    for(int k=2;k<=4;++k)
                    {
                        int u=st[j];
                        if(f[u]<g[nt[u][k]]+1)
                            f[u]=g[nt[u][k]]+1,zy[u]=nt[u][k];
                    }
                for(int j=1;j<=top;++j)g[st[j]]=f[st[j]];
                for(int j=2,nw=1;j<=top;++j)
                {
                    g[st[j]]=max(g[st[j]],f[st[nw]]+top-nw);
                    if(f[st[nw]]-nw<f[st[j]]-j)nw=j;
                }
                for(int j=top-1,nw=top;j>=1;--j)
                {
                    g[st[j]]=max(g[st[j]],f[st[nw]]+nw-1);
                    if(f[st[nw]]+nw<f[st[j]]+j)nw=j;
                }
            }
            for(int k=2;k<=4;++k)
                if(f[0]<=g[nt[0][k]])f[0]=g[nt[0][k]],zy[0]=nt[0][k];
            printf("%d
    ",f[0]);
            Output(zy[0],f[0]);puts("");
        }
    }
    namespace Task2
    {
    	struct Line{int v,next,w;}e[MAX<<5];
    	int h[MAX],cnt=2,M[MAX],SS,TT,S,T;
    	inline void Add(int u,int v,int w)
    	{
    		e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
    		e[cnt]=(Line){u,h[v],0};h[v]=cnt++;
    	}
    	set<pair<int,int> > SSS;
    	bool vis[MAX];
        void Link(int x,int ans,bool fl)
        {
    		if(!ans)return;
    		if(!fl)if(SSS.count(make_pair(x,ans)))return;
    		if(!fl)SSS.insert(make_pair(x,ans));
    		if(f[x]==ans&&!vis[x])
    		{
    			vis[x]=true;
    			for(int k=2;k<=4;++k)
    				if(f[x]==g[nt[x][k]]+1)
    				{
    					Add(x,nt[x][k],inf);
    					M[x]-=1;M[nt[x][k]]+=1;
    					Link(nt[x][k],ans-1,1);
    				}
    		}
    		if(!fl)return;
    		vector<int> st;int top=0;st.clear();st.push_back(0);
    		int pos=a[x];while(pos>1&&p[pos-1].y==p[a[x]].y)--pos;
            top=0;while(p[pos].y==p[a[x]].y&&pos<=n)st.push_back(p[pos++].id),++top;
            for(int i=1;i<=top;++i)if(st[i]==x){pos=i;break;}
            for(int i=1;i<pos;++i)if(f[st[i]]+top-i==g[x])Link(st[i],f[st[i]],0);
            for(int i=top;i>pos;--i)if(f[st[i]]+i-1==g[x])Link(st[i],f[st[i]],0);
        }
    	int level[MAX],cur[MAX];
    	bool bfs(int S,int T)
    	{
    		memset(level,0,sizeof(level));level[S]=1;
    		queue<int> Q;Q.push(S);
    		while(!Q.empty())
    		{
    			int u=Q.front();Q.pop();
    			for(int i=h[u];i;i=e[i].next)
    				if(e[i].w&&!level[e[i].v])
    					level[e[i].v]=level[u]+1,Q.push(e[i].v);
    		}
    		return level[T];
    	}
    	int dfs(int u,int T,int flow)
    	{
    		if(u==T||!flow)return flow;
    		int ret=0;
    		for(int &i=cur[u];i;i=e[i].next)
    		{
    			int v=e[i].v,d;
    			if(e[i].w&&level[v]==level[u]+1)
    			{
    				d=dfs(v,T,min(flow,e[i].w));
    				ret+=d;flow-=d;
    				e[i].w-=d;e[i^1].w+=d;
    				if(!flow)break;
    			}
    		}
    		return ret;
    	}
    	int Dinic(int S,int T)
    	{
    		int ret=0;
    		while(bfs(S,T))
    		{
    			memcpy(cur,h,sizeof(cur));
    			ret+=dfs(S,T,inf);
    		}
    		return ret;
    	}
    	int ans,rb;
    	void Solve()
    	{
    		S=n+1;T=n+2;SS=n+3;TT=n+4;
    		f[0]+=1;g[0]=inf;Link(0,f[0],0);
    		for(int i=0;i<=n;++i)Add(i,T,inf);
    		for(int i=0;i<=n;++i)Add(S,i,inf);
    		for(int i=0;i<=n;++i)
    			if(M[i]>0)Add(SS,i,M[i]);
    			else Add(i,TT,-M[i]);
    		Add(T,S,inf);rb=cnt-1;
    		Dinic(SS,TT);
    		h[T]=e[h[T]].next;h[S]=e[h[S]].next;
    		ans-=Dinic(T,S);ans+=e[rb].w;
    		printf("%d
    ",ans);
    	}
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read(),p[i].id=i;
        Task1::Solve();Task2::Solve();
    	return 0;
    }
    
    
  • 相关阅读:
    AIBigKaldi(十三)| Kaldi的三音子模型训练(下)(源码解析)
    AIBigKaldi(十二)| Kaldi的三音子模型训练(中)(源码解析)
    AIBigKaldi(十一)| Kaldi的三音子模型训练(上)(源码解析)
    AIBigKaldi(十)| Kaldi的thchs30实例(源码解析)
    AIBigKaldi(九)| Kaldi的解码搜索(源码解析)
    AIBigKaldi(八)| Kaldi的解码图构造(下)(源码解析)
    AIBigKaldi(七)| Kaldi的解码图构造(上)(源码解析)
    AIBigKaldi(六)| Kaldi的单音子模型训练(下)(源码解析)
    AIBigKaldi(五)| Kaldi的单音子模型训练(上)(源码解析)
    理解 Linux 的硬链接与软链接
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9288367.html
Copyright © 2011-2022 走看看