题意:主人和狗散步,主人走的路都是一段一段的线段,狗想要去有趣的地方,但是要在主人线路上的每个顶点处与主人汇合,而且每次最多只能去一个地方,狗的速度是主人速度的两倍。给定主人的路线(一些坐标点)和狗想去的有趣的地方,求出狗最多能走的路线上的顶点数,并且将这些点打印出来。
分析:对于每一段线段,狗和主人同时出发,然后在另一个端点汇合,其中就看有没有有趣的地方可以去,并且在规定时间里赶回来,也就是狗的路径长度 <= 主人的路径长度的2倍,然后构造二部图,集合X中是线段,集合Y中是点,如果点到两线段端点的距离之和 <= 线段的长度 ,就建立联系。套用匈牙利算法。
WA教训:依然是下标范围出错,没有对上号,由边找点,link是点指向边, 范围是点的范围,antiLink是反过来记录的,所以范围是边的范围。
存储方式:连接表。有点节省空间和时间,链接矩阵中有很多空联系,值是0,在存储和查找时都会浪费。链接表中只有存在的联系,可以节省空间和时间。
匈牙利算法时间节省的方法:匈牙利的算法有两层循环,将个数少的集合放在第一层循环可以节省时间,不过这也取决于连接表怎么建立的。
代码:
//uva670 The dog task
//AC By Warteac
//2013-4-21
//Runtime:0.016
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
//
struct node{
int x;
int y;
node(int a = 0,int b = 0){x = a; y = b;}
double distance(node n){return sqrt((double)(x-n.x)*(x-n.x)+(y-n.y)*(y-n.y));}
double distance(node n1,node n2){
return sqrt((double)(x-n1.x)*(x-n1.x)+(y-n1.y)*(y-n1.y)) + sqrt((x-n2.x)*(x-n2.x)+(y-n2.y)*(y-n2.y));
}
void printNode(){cout << x <<" "<< y;}
};
class TheDogTask{
private:
vector < vector <int> > map;//邻接表
int numOfBobRoute;
int numOfDogRoute;
vector <node> bobRoute;
vector <node> dogRoute;
private:
int matched;
vector <int> link;//从 dogRoute 到 bobRoute
vector <int> antiLink;//从bobRoute 到 dogRoute
vector <bool> visited;
bool dfs(int u);//寻找增广路径
public:
void initial();
void readCase();
void computing();
void outResult();
};
void TheDogTask::initial(){
map.clear();
bobRoute.clear();
dogRoute.clear();
link.clear();
antiLink.clear();
visited.clear();
numOfBobRoute = 0;
numOfDogRoute = 0;
matched = 0;
}
void TheDogTask::readCase(){
int n , m,x,y;
double dis;
vector <int> route;
cin >> n >> m;
numOfBobRoute = n;
numOfDogRoute = m;
while(n--){
cin >> x >> y;
bobRoute.push_back(node(x,y));
}
while(m--){
cin >> x >> y;
dogRoute.push_back(node(x,y));
}
for(int i = 0; i < numOfBobRoute - 1; i++){//遍历每条边
dis = bobRoute[i].distance(bobRoute[ i+1 ]);
route.clear();//CLEAR
for(int j = 0; j < numOfDogRoute; j++){//遍历每个有趣的地方
if(dogRoute[j].distance(bobRoute[i],bobRoute[ i+1 ]) <= 2 * dis){
route.push_back(j);//编号为j的地方dog可以去
}
}
map.push_back(route);//建立一行记录
}
}
bool TheDogTask::dfs(int u){
for(int j = 0; j < map[u].size(); j++){
//cout << " j = " << j <<endl;
int t = map[u][j];
if(!visited[t]){
visited[t] = true;
if(link[t] == -1 || dfs(link[t]) == true){
link[t] = u;
antiLink[u] = t;
return true;
}
}
}
return false;//退出循环后才return false-WA;
}
void TheDogTask::computing(){//hungary
for(int x = 0; x < numOfDogRoute; x++)
link.push_back(-1);
for(int x = 0; x < map.size(); x++)//antiLink的大小和link的大小不同-WA
antiLink.push_back(-1);
for(int i = 0; i < map.size(); i++){
//cout << " i = " << i <<endl;
visited.clear();
visited.resize(numOfDogRoute);
if(dfs(i)) matched++;
}
}
void TheDogTask::outResult(){
/*for (int i = 0; i < map.size(); i++){
for (int j = 0; j < map[i].size(); j++){
cout << map[i][j] << " ";
}
cout << endl;
}*/
cout << matched + numOfBobRoute << endl;
bobRoute[0].printNode();
for(int i = 0; i < map.size(); i++){
if(antiLink[i] != -1){
cout << " ";
dogRoute[antiLink[i]].printNode();
}
cout << " ";
bobRoute[i+1].printNode();
}
cout << endl;
}
//
int main(){
TheDogTask dt;
int n,m = 0;
cin >> n;
while(n--){
m++;
dt.initial();
dt.readCase();
dt.computing();
if(m > 1) cout << endl;
dt.outResult();
}
}