原题传送门
题目背景
Grant喜欢带着他的小狗Pandog散步。Grant以一定的速度沿着固定路线走,该路线可能自交。Pandog喜欢游览沿途的景点,不过会在给定的N个点和主人相遇。小狗和主人同时从(X1,Y1)点出发,并同时在(Xn,Yn)点汇合。小狗的速度最快是Grant的两倍。当主人从一个点以直线走向另一个点时,Pandog跑向一个它感兴趣的景点。Pandog每次与主人相遇之前最多只去一个景点。
题目描述
你现在的任务是:为Pandog寻找一条路线(有可能与主人的路线部分相同),使它能够游览最多的景点,并能够准时与主人在给定地点相遇或者汇合。
输入输出格式
输入格式:
输入文件第一行是两个整数N和M( 1≤N,M≤100 );
输入文件第二行的N个坐标给出了Grant的散步路线,即Pandog和主人相遇地点;
输入文件第三行的M个坐标给出了所有Pandog感兴趣的景点。
所有输入的坐标均不相同,且绝对值不超过1000。
输出格式:
输出小狗的移动路线。
第一行是经过的点数,第二行依次为经过的点的坐标(直角坐标系)
输入输出样例
输出样例#1:
6 1 4 3 9 5 7 5 2 1 2 -2 4
题解
前置知识二分图
这道题是要求输出方案的二分图匹配问题的模板题,思维难度不高,代码简单。
建模的方法很容易想到:
我们将景点作为左集合的元素,将每两个集合点见的空隙作为右集合的元素,
至于连边,我们只需要枚举每两个集合点见的空隙,再枚举每一个景点,如果来得及游玩就在两个点之间连边
最终询问的结果就是N+最大匹配数。
至于如何输出方案,只需要枚举并输出每一个集合点,如果该点与下一个点的空隙被匹配到了,就输出匹配到的景点
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long LL;
4 const int INF=1e9+7,MAXN=105,MAXM=MAXN*MAXN;
5 struct node{
6 int X,Y;
7 }A[MAXN],B[MAXN];
8 inline double dis(node x,node y){
9 double ii=x.X-y.X,jj=x.Y-y.Y;
10 return sqrt(ii*ii+jj*jj);
11 }
12 int N,M,ans;
13 int head[MAXN],to[MAXM],nxt[MAXM],tp;
14 inline void add(int x,int y){
15 nxt[++tp]=head[x];
16 head[x]=tp;
17 to[tp]=y;
18 }
19 int used[MAXN],match[MAXN];
20 bool dfs(int x){
21 for(int i=head[x];i;i=nxt[i]){
22 if(!used[to[i]]){
23 used[to[i]]=1;
24 if(!match[to[i]]||dfs(match[to[i]])){
25 match[to[i]]=x;
26 return 1;
27 }
28 }
29 }
30 return 0;
31 }
32 int main(){
33 scanf("%d%d",&N,&M);
34 for(int i=1;i<=N;i++){
35 scanf("%d%d",&A[i].X,&A[i].Y);
36 }
37 for(int i=1;i<=M;i++){
38 scanf("%d%d",&B[i].X,&B[i].Y);
39 }
40 for(int i=1;i<N;i++){
41 for(int j=1;j<=M;j++){
42 if(dis(A[i],A[i+1])*2.0>=dis(A[i],B[j])+dis(B[j],A[i+1])){
43 add(j,i);
44 }
45 }
46 }
47 for(int i=1;i<=M;i++){
48 memset(used,0,sizeof(used));
49 ans+=dfs(i);
50 }
51 printf("%d
",ans+N);
52 for(int i=1;i<=N;i++){
53 printf("%d %d ",A[i].X,A[i].Y);
54 if(match[i]){
55 printf("%d %d ",B[match[i]].X,B[match[i]].Y);
56 }
57 }
58 return 0;
59 }