zoukankan      html  css  js  c++  java
  • 51Nod 1331 狭窄的通道

    有一个长为L的狭窄通道,我们假设这个通道在x轴上,其两个出口分别在x=0与x=L处。在这个通道里有N只狼,第i只狼有一个初始位置ai,它想到达位置bi(0<=i<N)。但是这个通道太狭窄了不能允许两只狼相互交换位置他们的位置,因此如果两只狼需要交换它们的位置他们需要同时离开这个通道到x=0或x=L处在那里重新安排进通道的顺序。在x<=0与x>=L处空间足够大可以装下任意数量的狼。那么所有的狼想从ai到bi它们总共最少走多远的距离,输出这个距离。
    注意:在x<=0和x>=L的通道外部空间中移动的距离不计算在内;另外,x=0到x=L只能通过通道连通,即通道外面的世界不能从x=0走到x=L处。

    解题报告:
    用时:2h,2WA
    这题一开始想到按照起点排序,然后枚举一个断点,断点左边先全走到0(称之为左集合),右边((称为右集合)先全都走到L,然后问题来了,拍的时候发现有时候到终点的顺序还需要调整,也就是说还有一些狼需要从0走到L,也还有一些要从L走到0,本蒟蒻就不知道怎么处理了.
    参考题解:
    将左右两边分别都按终点从小到大排序,然后处理终点的矛盾,具体的我不清楚,我就乱写了个(O(n^2))的矛盾处理,在枚举了起点的断点的基础上,我再从右集合中枚举了终点的一个断点,设他的终点为t,把终点小于t的属于左集合的全部都移动到L中,并且把右边集合的中小于t的移动到0,这样矛盾就解决了
    然后发现还是不行,发现样例中还有直接从s移动到t的,于是我们选择判掉这一段,显然直接从s到t的必须是连续的一段区间,且左边的那矛盾的一段必须移动到0,右边的矛盾的一段必须移动到L,所以考虑枚举左边一段的终点和右边一段的起点,然后加上中间一段直接移动的即可
    复杂度:(O(n^3))

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=55,inf=2e8;
    int n,L;
    struct node{
    	int s,t;
    }a[N];
    bool comps(const node &p,const node &q){
    	return p.s<q.s;
    }
    bool compt(const node &p,const node &q){
    	return p.t<q.t;
    }
    int ans=2e8;
    void solve(int x){
    	int tot=0;
    	sort(a+1,a+x+1,compt);
    	sort(a+x+1,a+n+1,compt);
    	for(int i=1;i<=x;i++)
    		tot+=a[i].s+a[i].t;
    	for(int i=x+1;i<=n;i++)
    		tot+=L-a[i].s+L-a[i].t;
    	int tmp=0,tl=0;
    	for(int i=x+1;i<=n;i++){
    		tmp=0;
    		for(int j=1;j<=x;j++){
    			if(a[j].t>=a[i].t)tmp+=L-a[j].t+L-a[j].t;
    		}
    		ans=Min(ans,tot+tmp+tl);
    		tl+=a[i].t+a[i].t;
    	}
    }
    bool check(int l,int r,int sl,int sr){
    	int lm=0,rm=2e8;
    	for(int i=l;i<=r;i++)lm=Max(lm,a[i].t);
    	for(int i=sl;i<=sr;i++)rm=Min(rm,a[i].t);
    	return lm<rm;
    }
    void work()
    {
    	ans=2e8;
    	scanf("%d%d",&n,&L);
    	for(int i=1;i<=n;i++){
    		scanf("%d%d",&a[i].s,&a[i].t);
    	}
    	for(int i=0;i<=n;i++){
    		sort(a+1,a+n+1,comps);
    		solve(i);
    	}
    	sort(a+1,a+n+1,comps);
    	int si=0;
    	for(int i=0;i<=n;i++){
    		si+=a[i].t+a[i].s;
    		if(!check(1,i,i+1,n))continue;
    		int j=i+1,tot=0;
    		for(;j<=n;j++)
    			if(!check(i+1,j,j+1,n))break;
    		for(int k=i+1;k<j;k++)tot+=abs(a[k].t-a[k].s);
    		for(int k=j;k<=n;k++)tot+=L-a[k].s+L-a[k].t;
    		ans=Min(ans,si+tot);
    	}
    	printf("%d
    ",ans);
    }
    
    int main()
    {
    	int T;cin>>T;
    	while(T--)work();
    	return 0;
    }
    
  • 相关阅读:
    第一章:进销存系统基本功能
    SpringBoot 整合 Docker
    Java的脚本机制、编译器API
    Java 定时任务
    监听文件修改的四种方法
    SpringBoot Actuator — 埋点和监控
    Kafka消息队列
    OpenSSL配置HTTPS
    Java 国际化
    备忘录模式
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7535527.html
Copyright © 2011-2022 走看看