題目:主人帶著狗散步,主人走的路線由n-1個線段構成(n個點),主人和狗在所有線段重點匯合;
狗走的路線有兩種可能:1和主人走一樣的路線,2走到一個興趣點再回來(有m個興趣點);
狗的速度是主人的兩倍(興趣點到線段兩端的距離和不超過線段的2倍長),求狗走過的路徑;
要求狗走過最多的興趣點。
分析:圖論,二分圖匹配。路線線段和興趣點間的二分圖匹配問題,匈牙利算法。
由於狗走過的路線要麼是線段(和主人一樣),要麼走到一個興趣點在回來;
所以本體本質上是尋找,線段和點的最大匹配數(距離滿足要求的點);
建立組人走過的線段和興趣點間的二分圖,求解最大匹配即可;
說明:存在多解,輸出一組即可。注意每組數據間有空行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int route_x[101];
int route_y[101];
int place_x[101];
int place_y[101];
int g[202][202];
int used[202];
int link[202];
int dfs(int s, int n)
{
for (int i = 1; i <= n; ++ i) {
if (g[s][i] && !used[i]) {
used[i] = 1;
if (link[i] == -1 || dfs(link[i], n)) {
link[i] = s;
return 1;
}
}
}
return 0;
}
double dist(int x1, int y1, int x2, int y2)
{
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) +0.0);
}
int main()
{
int t, n, m;
while (~scanf("%d",&t))
while (t --) {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; ++ i) {
scanf("%d%d",&route_x[i],&route_y[i]);
}
for (int i = 1; i <= m; ++ i) {
scanf("%d%d",&place_x[i],&place_y[i]);
}
// create graph
memset(g, 0, sizeof(g));
double d1, d2, d3;
for (int i = 1; i < n; ++ i) {
d1 = dist(route_x[i+1], route_y[i+1], route_x[i], route_y[i]);
for (int j = 1; j <= m; ++ j) {
d2 = dist(route_x[i+1], route_y[i+1], place_x[j], place_y[j]);
d3 = dist(route_x[i], route_y[i], place_x[j], place_y[j]);
if (2.0*d1+1e-8 > d2+d3) {
g[i][j+n-1] = 1;
g[j+n-1][i] = 1;
}
}
}
// Hungarian Algorithm
int sum = 0;
memset(link, -1 ,sizeof(link));
for(int i = 1; i < m+n; ++ i) {
memset(used, 0, sizeof(used));
sum += dfs(i, m+n-1);
}
printf("%d\n%d %d",sum/2+n,route_x[1],route_y[1]);
for (int i = 2; i <= n; ++ i) {
int index = link[i-1];
if (index != -1) {
printf(" %d %d",place_x[index-n+1],place_y[index-n+1]);
}
printf(" %d %d",route_x[i],route_y[i]);
}
puts("");
if (t) {
puts("");
}
}
return 0;
}