UVa 670 - The dog task

題目:主人帶著狗散步,主人走的路線由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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值