F (6). 小狗散步(二分图,匈牙利算法)

题目描述

李旭琳喜欢带着她的小狗Candy散步。李旭琳以一定的速度沿着固定路线走,该路线可能自交。Candy喜欢游览沿途的景点,不过会在给定的N个点和主人相遇。小狗和李旭琳同时从(x_1,y_1)点出发,并同时在(x_n,y_n)点汇合。小狗的速度最快是李旭琳的两倍。当主人从一个点以直线走向另一个点时,Candy跑向一个它感兴趣的景点。Candy每次与李旭琳相遇之前最多只去一个景点。 
你现在的任务是:为Candy寻找一条路线(有可能与主人的路线部分相同),使它能够游览最多的景点,并能够准时与主人在给定地点相遇或者汇合。

输入描述

输入第一行是两个整数N和M(1≤N,M≤100);
输入第二行的N个坐标给出了李旭琳的散步路线,即Candy和主人相遇地点;
输入第三行的M个坐标给出了所有Candy感兴趣的景点。
所有输入的坐标均不相同,且绝对值不超过1 000。

输出描述

输出小狗的移动路线。
第一行是经过的点数,第二行依次为经过的点的坐标(直角坐标系)。

分析:

        由题,我们可以把主人想去的和小狗想去的点分别分为两组,构成一个二分图,之后对于每一个节点遍历,当 主人想去的两相邻结点之间的距离*2 \geq 小狗想去的点到两点之间的距离之和 时,我们认为,这两个结点之间可以使用一条边相连,即小狗可以在中途访问小狗想去的节点,然后再跑回主人要去的下一节点,而最大匹配数为小狗能多看的小狗想去的点,小狗经过的节点数即为 最大匹配数+主人要去的结点数,之后按照最大匹配中记录的边,对其依次输出。

代码:

#include<bits/stdc++.h>
using namespace std;
#define N 1000
#define fi first
#define se second
typedef pair<int,int> PII;
 
bool d[N][N],vis[N];
int p[N];
int n,m;
pair<int,int> a[N],b[N];
 
bool match(int e) {
	for(int i=1; i<=n; i++) {
		if(vis[i]||!d[e][i])
			continue;
		vis[i]=true;
		if(p[i]==0||match(p[i])) {
			p[i]=e;
			return true;
		}
	}
	return false;
}
int cma() {
	int cnt=0;
	for(int i=1; i<=m; i++) {
		memset(vis,false,sizeof vis);
		if(match(i))
			cnt++;
	}
	return cnt;
}
double f(PII a,PII b) {
	double x=a.fi-b.fi;
	double y=a.se-b.se;
	return sqrt(x*x*1.0+y*y*1.0);
}//计算路径长度
void print(PII a) {
	cout<<a.fi<<" "<<a.se<<" ";
}//out
 
int main() {
	cin>>n>>m;
	for(int i=1; i<=n; i++)
		cin>>a[i].fi>>a[i].se;
	for(int i=1; i<=m; i++)
		cin>>b[i].fi>>b[i].se;
	for(int i=1; i<n; i++) {
		double t=f(a[i],a[i+1])*2;//两相邻节点间距
		for(int j=1; j<=m; j++) {
			double b_t=f(a[i],b[j])+f(a[i+1],b[j]);//小狗跑去跑回的距离
			if(t>=b_t)
				d[j][i]=true;
		}
	}
	int cnt=cma()+n;
	cout<<cnt<<"\n";
	for(int i=1; i<=n; i++) {
		print(a[i]);
		if(p[i])
			print(b[p[i]]);
	}
	return 0;
}
 
/*
解决方案: 875836
问题: 竞赛3162:F (6)
用户: 20222203362
判题类型: acm
提交时间: 2023-05-29 20:09:26
时间: 13MS
空间: 0.67MB
语言: C++20
代码长度: 1121B
判题时间: 2023-05-29 20:09:26
 
panjyash原创 拒绝转载!!!
*/

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

panjyash

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值