BZOJ4200 & 洛谷2304 & UOJ132:[NOI2015]小园丁与老司机——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4200

https://www.luogu.org/problemnew/show/P2304

http://uoj.ac/problem/132

小园丁 Mr. S 负责看管一片田野,田野可以看作一个二维平面。田野上有 nn 棵许愿树,编号 1,2,3,…,n1,2,3,…,n,每棵树可以看作平面上的一个点,其中第 ii 棵树 (1≤i≤n1≤i≤n) 位于坐标 (xi,yi)(xi,yi)。任意两棵树的坐标均不相同。
老司机 Mr. P 从原点 (0,0)(0,0) 驾车出发,进行若干轮行动。每一轮,Mr. P 首先选择任意一个满足以下条件的方向:
为左、右、上、左上 45∘45∘ 、右上 45∘45∘ 五个方向之一。
沿此方向前进可以到达一棵他尚未许愿过的树。
完成选择后,Mr. P 沿该方向直线前进,必须到达该方向上距离最近的尚未许愿的树,在树下许愿并继续下一轮行动。如果没有满足条件的方向可供选择,则停止行动。他会采取最优策略,在尽可能多的树下许愿。若最优策略不唯一,可以选择任意一种。
不幸的是,小园丁 Mr. S 发现由于田野土质松软,老司机 Mr. P 的小汽车在每轮行进过程中,都会在田野上留下一条车辙印,一条车辙印可看作以两棵树(或原点和一棵树)为端点的一条线段。
在 Mr. P 之后,还有很多许愿者计划驾车来田野许愿,这些许愿者都会像 Mr. P 一样任选一种最优策略行动。Mr. S 认为非左右方向(即上、左上 45∘45∘ 、右上 45∘45∘ 三个方向)的车辙印很不美观,为了维护田野的形象,他打算租用一些轧路机,在这群许愿者到来之前夯实所有“可能留下非左右方向车辙印”的地面。
“可能留下非左右方向车辙印”的地面应当是田野上的若干条线段,其中每条线段都包含在某一种最优策略的行进路线中。每台轧路机都采取满足以下三个条件的工作模式:
从原点或任意一棵树出发。
只能向上、左上 45∘45∘ 、右上 45∘45∘ 三个方向之一移动,并且只能在树下改变方向或停止。
只能经过“可能留下非左右方向车辙印”的地面,但是同一块地面可以被多台轧路机经过。
现在 Mr. P 和 Mr. S 分别向你提出了一个问题:
请给 Mr .P 指出任意一条最优路线。
请告诉 Mr. S 最少需要租用多少台轧路机。

哈哈哈我可能是疯了所以才去做了码农题,然后dp不会最小流写跪哈哈哈

直接看这个吧,心累到懒得讲题解了:https://blog.csdn.net/litble/article/details/80463466

另外开O2的时候普通的最小流也可以通过,不开的时候就会奇妙RE。

(自认码风不错)

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=1e9;
const int N=5e4+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct point{
    int x,y,b1,b2,id;
}p[N];
int n,b[N],c[N],d[N],e[N],l1,l2,l3,l4;
int to[3][N],lft[N],straight[N],rigt[N];
int f[N],g[N],flor[N],num[N];
vector<int>ty[N];
inline bool cmpx(point a,point b){
    return a.x<b.x;
}
inline bool cmpy(point a,point b){
    return a.y>b.y;
}
void LSH(){
    sort(b+1,b+l1+1);sort(c+1,c+l2+1);
    sort(d+1,d+l3+1);sort(e+1,e+l4+1);
    l1=unique(b+1,b+l1+1)-b-1,l2=unique(c+1,c+l2+1)-c-1;
    l3=unique(d+1,d+l3+1)-d-1,l4=unique(e+1,e+l4+1)-e-1;
    for(int i=1;i<=n;i++){
    p[i].x=lower_bound(b+1,b+l1+1,p[i].x)-b;
    p[i].y=lower_bound(c+1,c+l2+1,p[i].y)-c;
    p[i].b1=lower_bound(d+1,d+l3+1,p[i].b1)-d;
    p[i].b2=lower_bound(e+1,e+l4+1,p[i].b2)-e;
    }
}
void init(){
    LSH();
    sort(p+1,p+n+1,cmpy);
    for(int i=1;i<=n;i++){
    int id=p[i].id;
    to[0][id]=lft[p[i].b2];
    to[1][id]=straight[p[i].x];
    to[2][id]=rigt[p[i].b1];
    lft[p[i].b2]=id;
    straight[p[i].x]=id;
    rigt[p[i].b1]=id;
    }
    sort(p+1,p+n+1,cmpx);
    for(int i=1;i<=n;i++){
    ty[p[i].y].push_back(p[i].id);
    flor[p[i].id]=p[i].y;
    num[p[i].id]=ty[p[i].y].size()-1;
    }
}
int pre[N],lrs[N];
void output(int id){
    if(id!=lrs[id]){
    int fll=flor[id];
    if(num[id]<num[lrs[id]]){
        for(int i=num[id]-1;i>=0;i--)printf("%d ",ty[fll][i]);
        for(int i=num[id]+1;i<=num[lrs[id]];i++)printf("%d ",ty[fll][i]);
    }else{
        int sz=ty[fll].size();
        for(int i=num[id]+1;i<sz;i++)printf("%d ",ty[fll][i]);
        for(int i=num[id]-1;i>=num[lrs[id]];i--)printf("%d ",ty[fll][i]);
    }
    }
    id=lrs[id];
    if(pre[id]){
    printf("%d ",pre[id]);
    output(pre[id]);
    }
}
void work1(){
    init();
    for(int i=l2;i>=1;i--){
    int maxn=0,id=0,sz=ty[i].size();
    for(int j=0;j<sz;j++){//处理直行和向右再左走
        int I=ty[i][j];
        int J1=to[0][I],J2=to[1][I],J3=to[2][I];
        if(J1&&g[I]<f[J1])g[I]=f[J1],pre[I]=J1;
        if(J2&&g[I]<f[J2])g[I]=f[J2],pre[I]=J2;
        if(J3&&g[I]<f[J3])g[I]=f[J3],pre[I]=J3;
        if(maxn>g[I]+1)f[I]=maxn,lrs[I]=id;
        else f[I]=g[I]+1,lrs[I]=I;
        if(sz-j+g[I]>maxn)maxn=sz-j+g[I],id=I;
    }
    maxn=id=0;
    for(int j=sz-1;j>=0;j--){//处理向左再右走
        int I=ty[i][j];
        if(maxn>f[I])f[I]=maxn,lrs[I]=id;
        if(g[I]+j+1>maxn)maxn=g[I]+j+1,id=I;
    }
    }
    printf("%d\n",f[n]-1);output(n);puts("");
}
struct node{
    int to,nxt,w;
}edge[N*10];
int cnt,head[N],S,T,du[N];
int cur[N],lev[N],dui[N];
bool ok[N];
inline void adde(int u,int v,int w){
    edge[++cnt].to=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt;
    edge[++cnt].to=u;edge[cnt].w=0;edge[cnt].nxt=head[v];head[v]=cnt;
}
inline void add(int u,int v){
    for(int i=head[u];i!=-1;i=edge[i].nxt)
    if(edge[i].to==v)return;
    du[u]--;du[v]++;adde(u,v,INF-1);
}
bool bfs(int m){
    int r;
    for(int i=1;i<=m;i++){
    cur[i]=head[i];lev[i]=-1;
    }
    dui[r=0]=S;lev[S]=0;
    for(int i=0;i<=r;i++){
    int u=dui[i];
    for(int j=head[u];j!=-1;j=edge[j].nxt){
        int v=edge[j].to,w=edge[j].w;
        if(lev[v]==-1&&w){
        lev[v]=lev[u]+1;
        dui[++r]=v;
        if(v==T)return 1;
        }
    }
    }
    return 0;
}
int dinic(int u,int flow,int m){
    if(u==m)return flow;
    int res=0,delta;
    for(int &i=cur[u];i!=-1;i=edge[i].nxt){
    int v=edge[i].to;
    if(lev[v]>lev[u]&&edge[i].w){
        delta=dinic(v,min(flow,edge[i].w),m);
        if(delta){
        edge[i].w-=delta;
        edge[i^1].w+=delta;
        res+=delta;
        if(res==flow)break;
        }
    }
    }
    if(res!=flow)lev[u]=-1;
    return res;
}
void build(){
    ok[n]=1;
    for(int i=1;i<=l2;i++){
    int sz=ty[i].size();
    for(int j=0;j<sz;j++){
        int I=ty[i][j];
        if(!ok[I])continue;
        for(int k=0;k<j;k++){
        int J=ty[i][k];
        int K1=to[0][J],K2=to[1][J],K3=to[2][J];
        if(K1&&f[K1]+sz-k==f[I])add(J,K1),ok[K1]=1;
        if(K2&&f[K2]+sz-k==f[I])add(J,K2),ok[K2]=1;
        if(K3&&f[K3]+sz-k==f[I])add(J,K3),ok[K3]=1;
        }
        for(int k=j+1;k<sz;k++){
        int J=ty[i][k];
        int K1=to[0][J],K2=to[1][J],K3=to[2][J];
        if(K1&&f[K1]+k+1==f[I])add(J,K1),ok[K1]=1;
        if(K2&&f[K2]+k+1==f[I])add(J,K2),ok[K2]=1;
        if(K3&&f[K3]+k+1==f[I])add(J,K3),ok[K3]=1;
        }
        int K1=to[0][I],K2=to[1][I],K3=to[2][I];
        if(K1&&f[K1]+1==f[I])add(I,K1),ok[K1]=1;
        if(K2&&f[K2]+1==f[I])add(I,K2),ok[K2]=1;
        if(K3&&f[K3]+1==f[I])add(I,K3),ok[K3]=1;
    }
    }
}
void work2(){
    memset(head,-1,sizeof(head));cnt=-1;
    build();
    S=n+1,T=S+1;
    int ans=0;
    for(int i=1;i<=n;i++){
    if(du[i]>0)adde(S,i,du[i]),ans+=du[i];
    else if(du[i]<0)adde(i,T,-du[i]);
    }
    while(bfs(T))ans-=dinic(S,INF,T);
    printf("%d\n",ans);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
    p[i].x=b[++l1]=read();
    p[i].y=c[++l2]=read();
    p[i].b1=d[++l3]=p[i].y-p[i].x;
    p[i].b2=e[++l4]=p[i].y+p[i].x;
    p[i].id=i;
    }
    p[++n].x=b[++l1]=0;
    p[n].y=c[++l2]=0;
    p[n].b1=d[++l3]=0;
    p[n].b2=e[++l4]=0;
    p[n].id=n;
    work1();work2();
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

猜你喜欢

转载自www.cnblogs.com/luyouqi233/p/9140050.html