zoukankan      html  css  js  c++  java
  • 并不对劲的loj2134:uoj132:p2304:[NOI2015]小园丁与老司机

    题目大意

    给出平面直角坐标系中(n)((nleq5*10^4))个点,第(i)个点的坐标是(x_i,y_i(|x_i|leq10^9,1leq y_ileq10^9)),只有朝正上方、正左方、正右方、右上方45°、左上方45°走的路,只能在给出的点处拐弯
    解决两个问题:
    1.从点((0,0))出发,只能在没走到过的点处拐弯,求最多能走多少个给出的点并输出方案
    2.从点((0,0))或者任意一个给出的点出发,不能朝正左方、正右方走,而且只能走被一种第1问的最优方案包含的路,求至少要走几次才能覆盖所有被一种第1问的最优路线包含了的路

    题解

    先预处理每个点朝正上方、正左方、正右方、右上方45°、左上方45°走遇到的第一个点
    1.
    (y_i)相同的点归为同一层
    (f(i))表示如果从点(i)进入(i)所在的那一层,那么在(i)所在的层和上面的层最多能走多少给出的点
    发现如果从(i)进入某一层,从(j)离开这一层,那么当(i<j)时该层最多走(j)左边所有点,当(i>j)时该层最多走(j)右边所有点,(i=j)时只会走到一个点
    这是因为当(i<j)时,可以先向左走,走到(i)左边所有点,再向右走,走(i,j)之间的所有点(答案不少于(j)左边所有点)
    而如果走到了(j)右边的点,就一定会走过(j),无法再从(j)离开这一层了(答案不多于(j)左边所有点)
    (i>j)时同理
    (h(x))表示点(x)左上方45°的第一个点、右上方45°的第一个点、正上方的第一个点的(f)的最大值
    那就有(f(i)=max(max{h(j)+(j左边的点数)mid i<j},max{h(j)+(j右边的点数)mid i>j},max{h(j)+1mid i=j}))
    (f(0))就是第一问的答案
    递推(f)时要记方案
    2.
    (g(i))表示如果从点(i)离开(i)所在的那一层,那么离开时在(i)所在的层和下面的层最多能走多少给出的点
    会发现对于一个点(i),它 左上方45°的第一个点 或 右上方45°的第一个点 或 正上方的第一个点 (j)如果满足(g(i)+f(j)=f(0))那么(i->j)就是一条出现在第一问最优方案中的路
    发现这个可以是个有上下界最小流,每条路看成下界为1,上界为(infty)的边
    也就是连上界为(infty)的边,算出每个点的出入度后,出>入的连(该点->超汇)且上界为(出-入)的边,出<入的连(超源->该点)且上界为(入-出)的边
    通过观察题意发现这题一定有解,满流就是超源到所有点的上界之和(也是所有点到超汇的上界之和),那就可以直接用(满流时的流量-重新建图后的流量)

    代码
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
    #define maxn 50010
    #define maxm (maxn*8)
    #define LL long long 
    #define pre(x) (!maxto[ord[x]]?tl-x+1:f[maxto[ord[x]]]+tl-x+1)
    #define suf(x) (!maxto[ord[x]]?x-hd+1:f[maxto[ord[x]]]+x-hd+1)
    #define now(x) (!maxto[ord[x]]?1:f[maxto[ord[x]]]+1)
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        if(x==0){putchar('0');return;}
        int f=0;char ch[20];
        if(x<0)putchar('-'),x=-x;
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        return;
    }
    int n,xi[maxn],yi[maxn],ord[maxn],up[maxn][3],f[maxn],g[maxn],t[maxn],maxto[maxn],out[maxn],rnk[maxn],maxflow,full;
    int fir[maxn],nxt[maxm],dis[maxn],v[maxm],fl[maxm],cnt,in[maxn],S,T,inf=2147483647;
    bool cmpl(int x,int y){return (xi[x]+yi[x]==xi[y]+yi[y])?(yi[x]<yi[y]):(xi[x]+yi[x]<xi[y]+yi[y]);}
    bool cmpr(int x,int y){return (xi[x]-yi[x]==xi[y]-yi[y])?(yi[x]<yi[y]):(xi[x]-yi[x]<xi[y]-yi[y]);}
    bool cmpx(int x,int y){return (xi[x]==xi[y])?(yi[x]<yi[y]):(xi[x]<xi[y]);}
    bool cmpy(int x,int y){return (yi[x]==yi[y])?(xi[x]<xi[y]):(yi[x]>yi[y]);}
    void ade(int u1,int v1,int fl1)
    {
        v[cnt]=v1,nxt[cnt]=fir[u1],fl[cnt]=fl1,fir[u1]=cnt++;
        v[cnt]=u1,nxt[cnt]=fir[v1],fl[cnt]=0,fir[v1]=cnt++;
    }
    int hd,tl,q[maxn];
    int bfs()
    {
        hd=1,tl=0;
        rep(i,0,T)dis[i]=inf;
        dis[T]=0,q[++tl]=T;
        while(hd<=tl)
        {
            int u=q[hd++];
            view(u,k)if(fl[k^1]&&dis[v[k]]==inf)dis[v[k]]=dis[u]+1,q[++tl]=v[k];
        }
        return dis[S]==inf?0:1;
    }
    int getf(int u,int nowflow)
    {
        if(u==T||nowflow==0)return nowflow;
        int tmp,sum=0;
        view(u,k)
        {
            if(!nowflow)break;
            if(dis[v[k]]==dis[u]-1&&fl[k]&&(tmp=getf(v[k],min(nowflow,fl[k]))))fl[k]-=tmp,fl[k^1]+=tmp,nowflow-=tmp,sum+=tmp;
        }
        return sum;
    }
    int main()
    {
        memset(fir,-1,sizeof(fir));
        n=read();
        rep(i,1,n)xi[i]=read(),yi[i]=read(),ord[i]=i;
        sort(ord,ord+n+1,cmpl);
        rep(i,0,n-1){if(xi[ord[i+1]]+yi[ord[i+1]]==xi[ord[i]]+yi[ord[i]])up[ord[i]][0]=ord[i+1];}
        sort(ord,ord+n+1,cmpr);
        rep(i,0,n-1){if(xi[ord[i+1]]-yi[ord[i+1]]==xi[ord[i]]-yi[ord[i]])up[ord[i]][1]=ord[i+1];}
        sort(ord,ord+n+1,cmpx);
        rep(i,0,n-1){if(xi[ord[i+1]]==xi[ord[i]])up[ord[i]][2]=ord[i+1];}
        sort(ord,ord+n+1,cmpy);int pos;
        rep(i,0,n)
        {
            hd=i,tl=i;
            while(tl+1<=n&&yi[ord[tl+1]]==yi[ord[hd]])tl++;
            rep(j,hd,tl)rep(k,0,2){if(up[ord[j]][k]&&(!maxto[ord[j]]||f[up[ord[j]][k]]>f[maxto[ord[j]]]))maxto[ord[j]]=up[ord[j]][k];}
            pos=-1;
            rep(j,hd,tl)f[ord[j]]=now(j),out[ord[j]]=(!maxto[ord[j]])?-1:ord[j],rnk[ord[j]]=j;
            rep(j,hd,tl)
            {
                if(pos!=-1&&pre(pos)>f[ord[j]])f[ord[j]]=pre(pos),out[ord[j]]=ord[pos];
                if(pos==-1||pre(j)>pre(pos))pos=j;			
            }pos=-1;
            dwn(j,tl,hd)
            {
                if(pos!=-1&&suf(pos)>f[ord[j]])f[ord[j]]=suf(pos),out[ord[j]]=ord[pos];
                if(pos==-1||suf(j)>suf(pos))pos=j;	
            }
            i=tl;
        }
        //rep(i,0,n)cout<<"maxto:"<<maxto[i]<<" out:"<<out[i]<<endl;
        write(f[0]-1),putchar('
    ');
        pos=maxto[0]; 
        if(maxto[0])
        {
    	    do
    	    {
    	        if(rnk[out[pos]]<rnk[pos])
    	        {
    	            for(int i=rnk[pos];yi[ord[i]]==yi[pos];i++)write(ord[i]),putchar(' ');
    	            for(int i=rnk[pos]-1;yi[ord[i]]==yi[pos]&&i>=rnk[out[pos]];i--)write(ord[i]),putchar(' ');		
    	        }
    	        else if(rnk[out[pos]]>rnk[pos])
    	        {
    	            for(int i=rnk[pos];yi[ord[i]]==yi[pos];i--)write(ord[i]),putchar(' ');
    	            for(int i=rnk[pos]+1;yi[ord[i]]==yi[pos]&&i<=rnk[out[pos]];i++)write(ord[i]),putchar(' ');		
    	        }
    	        else write(pos),putchar(' ');
    	        pos=out[pos];
    	        if(out[pos]==-1)break;
    	        pos=maxto[pos];
    	    }while(pos);
       		putchar('
    ');
    	}
        rep(i,0,n)t[i]=g[i]=-n*4;g[0]=1;
        dwn(i,n,0)
        {
            hd=i,tl=i;
            while(hd-1>=0&&yi[ord[hd-1]]==yi[ord[tl]])hd--;
            pos=-1;
            rep(j,hd,tl)if(t[ord[j]]>0)g[ord[j]]=t[ord[j]]+1;
            rep(j,hd,tl)
            {
                if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+j-hd+1);
                if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
            }pos=-1;
            dwn(j,tl,hd)
            {
                if(pos!=-1)g[ord[j]]=max(g[ord[j]],t[ord[pos]]+tl-j+1);
                if(t[ord[j]]>0&&(pos==-1||t[ord[pos]]<t[ord[j]]))pos=j;
            }
            rep(j,hd,tl)if(g[ord[j]]>0){rep(k,0,2)if(up[ord[j]][k])t[up[ord[j]][k]]=max(t[up[ord[j]][k]],g[ord[j]]);}
            i=hd;
        }
        S=n+1,T=n+2;
        rep(i,0,n)rep(k,0,2)if(up[i][k]&&g[i]>0&&g[i]+f[up[i][k]]==f[0])in[i]--,in[up[i][k]]++,ade(i,up[i][k],inf);
        rep(i,0,n)
        {
            if(in[i]<0)ade(i,T,-in[i]);
            if(in[i]>0)ade(S,i,in[i]),full+=in[i];
        }
        while(bfs())maxflow+=getf(S,inf);write(full-maxflow);
        return 0;
    }
    /*
    6
    -1 1
    1 1
    -2 2
    0 8
    0 9
    0 10
    */
    /*
    4
    0 1
    -2 1
    2 1
    3 2
    */
    
  • 相关阅读:
    网页快捷键
    2016年5月3日15:55:23笔记
    【编程的乐趣-用python解算法谜题系列】谜题一 保持一致
    重温离散系列②之良序原理
    重温离散系列①之什么是证明
    浅谈栈和队列
    [leetcode]16-最接近的三数之和
    [leetcode] 4-寻找两个有序数组的中位数
    英语句子的基本结构【转】
    [leetcode] 11-盛最多水的容器
  • 原文地址:https://www.cnblogs.com/xzyf/p/10430451.html
Copyright © 2011-2022 走看看