uva 670The dog task

题意:主人和狗散步,主人走的路都是一段一段的线段,狗想要去有趣的地方,但是要在主人线路上的每个顶点处与主人汇合,而且每次最多只能去一个地方,狗的速度是主人速度的两倍。给定主人的路线(一些坐标点)和狗想去的有趣的地方,求出狗最多能走的路线上的顶点数,并且将这些点打印出来。

分析:对于每一段线段,狗和主人同时出发,然后在另一个端点汇合,其中就看有没有有趣的地方可以去,并且在规定时间里赶回来,也就是狗的路径长度  <=  主人的路径长度的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();
	}
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值