1 条题解

  • 0
    @ 2025-8-24 21:38:41

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 06ray
    再见了,OI

    搬运于2025-08-24 21:38:41,当前版本为作者最后更新于2018-09-01 22:15:28,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    又是一道二分图水题。

    这题关键在于如何建图以及输出方案。

    根据题意得知,每次狗在主人相遇之前最多去一个景点。那我们不妨枚举所有的景点,判断狗从上一个相遇点出发,经过这个景点,最后是否比主人先到达下一个相遇点。

    如果先到达,那我们就把下一个相遇点与这个景点连一条边。

    建图之后,我们只要用最大流求出最大匹配并加上N就是第一个答案了,Dinic最大流板子不讲。

    那么答案的第二行怎么求呢?很简单,先输出每个相遇点坐标,然后循环每个与它相连的景点,判断这条边的流量是否为0,如果是,就说明这个相遇点与景点匹配上了,输出景点的坐标。

    无比丑陋的代码:

    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <cmath>
    using namespace std;
    struct map{ //结构体存坐标 
       int x,y;
    };
    map a[1010],b[1010];//相遇点坐标以及景点坐标 
    const int MAX=0x7fffffff;
    int dis[1001000];
    int n,m,s,t;
    int head[600100],net[600100],to[600100],cap[600100];//前向星存图 
    int cnt=1;
    void add(int x,int y,int c)//最大流建边 
    {
       to[++cnt]=y;
       cap[cnt]=c;
       net[cnt]=head[x];
       head[x]=cnt;
       to[++cnt]=x;
       cap[cnt]=0;
       net[cnt]=head[y];
       head[y]=cnt;
    }
    int BFS()//Dinic最大流板子 
    {
        memset(dis,0,sizeof(dis));
        dis[s]=1;
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
           int v=q.front();
           q.pop();
           for(int i=head[v];i;i=net[i])
           {
               if(dis[to[i]]==0&&cap[i]>0)
               {
                   dis[to[i]]=dis[v]+1; 
                   q.push(to[i]);
               }
           }
    
        }
        if(dis[t]>0) return 1;
        return 0;
    }
    int find(int x,int low)
    {
       int a=0;
       if(x==t)return low;
       int sum=0;
       for(int i=head[x];i;i=net[i])
       {
           if(dis[to[i]]==dis[x]+1&&cap[i]!=0&&(a=find(to[i],min(low,cap[i]))))
           {
               cap[i]-=a;
               cap[i^1]+=a;
               low-=a;
               sum+=a;
               if(low==0)
               break;
           }
       }  
       return sum;
    }
    double js(map a,map b)//求出两点距离 
    {
       return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    int main()
    {
       int n;
       cin>>n>>m;
       for(int i=1; i<=n; i++)
       {
       	cin>>a[i].x>>a[i].y;
       }
       for(int i=1; i<=m; i++)
       {
       	cin>>b[i].x>>b[i].y;
       }
       s=0,t=n+m+1;//源点为0,汇点为n+m+1 
       for(int i=2; i<=n; i++)
       {
       	add(s,i,1);//将源点连接所有相遇点 
       	for(int j=1; j<=m; j++)
       	{
       		if(i==2) add(n+j,t,1);//将所有景点连接汇点 
       		if(js(a[i],a[i-1])>(js(a[i-1],b[j])+js(b[j],a[i]))/2.0)//如果狗从上一个相遇点出发,经过这个景点,最后比主人先到达这个相遇点 
       		{
       			add(i,n+j,1);//将这个相遇点连接这个景点 
       		}
       	}
       }
       int ans=0,tans=0;
       while(BFS())
       {
             while(tans=find(s,0x7fffffff)) ans+=tans;
       }
       cout<<ans+n<<endl;//输出第一个答案, 
       cout<<a[1].x<<' '<<a[1].y<<' ';//第一个相遇点要先输出 
       for(int i=2; i<=n; i++)
       {
       	for(int j=head[i]; j; j=net[j])
       	if(!cap[j]&&to[j]!=s)//如果这个点是景点且边流量为0 
       	{
       		cout<<b[to[j]-n].x<<' '<<b[to[j]-n].y<<' ';//输出景点坐标 
       		break; 
       	}
       	cout<<a[i].x<<' '<<a[i].y<<' ';//输出相遇点坐标 
       }
       return 0;
    }
    
    • 1

    信息

    ID
    1564
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者