poj 1034 The dog task

本文介绍了一个关于小狗沿特定轨迹访问最多点的问题,并将其转化为二分图最大匹配问题进行解决,通过匈牙利算法实现了匹配,最终输出小狗能够访问到的最多点数及其路径。
 题目大意:在二维坐标系中,存在由n个点构成的轨迹L,从第1个点依次到第n个点。又存在m个点。主人以1单位的速度沿着轨迹L前进,主人又带了一条狗,小狗的速度为2单位,主人和狗共同从第1个点出发。小狗在主人从第i个点走到第i+1个点的途中可以到达m个点中的任意某个点,但必须满足在主人到达第i+1个点之前到达该点,并最多只能访问1个点。问小狗所能达到的最多的点数,并输出小狗的行走路线。

思路:由于有第i个到第i+1个点最多只能访问1个属于m的点,所以该问题就转化为二分图的最大匹配问题。套模板即可。

另外说明下匈牙利算法的核心思路:假设存在四个节点n1,n2,m1,m2;E={(n1,m1), (n1,m2), (n2,m1), (n2,m2)};一开始匹配n1-m1成功;第二次匹配n2-m1,由于n1-m2也能匹配,则删去匹配n1-m1,增加匹配n1-m2, n2-m1,匹配成功,此时的增广路P=m2->n1->m1->n2。

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;

struct Point
{
    int x,y;
}node_set_n[105],node_set_m[105];

int m,n;
bool graph[105][105],have_visited[105];
int link[105],ans[105];

double cal_distance(struct Point p1,struct Point p2)
{
    double dx=(double)p1.x-p2.x;
    double dy=(double)p1.y-p2.y;
    return sqrt(dx*dx+dy*dy);
}

int dfs(int node_n)
{
    int node_m;
    for (node_m=1;node_m<=m;node_m++)
        if (graph[node_n][node_m] && have_visited[node_m]==false)
        {
            have_visited[node_m]=true;
            if (link[node_m]==-1 || dfs(link[node_m]))
            {
                link[node_m]=node_n;
                ans[node_n]=node_m;
                return 1;
            }
        }
    return 0;
}

int max_match()
{
    int i,match_num=0;
    memset(link,-1,sizeof(link));
    memset(ans,-1,sizeof(ans));
    for (i=1;i<=n;i++)
    {
        memset(have_visited,false,sizeof(have_visited));
        if (dfs(i))
            match_num++;
    }
    return match_num;
}

int main()
{
    int i,j;
    double len;
    while (scanf("%d%d",&n,&m)==2)
    {
        memset(graph,false,sizeof(graph));
        for (i=1;i<=n;i++)
            scanf("%d%d",&node_set_n[i].x,&node_set_n[i].y);
        for (i=1;i<=m;i++)
            scanf("%d%d",&node_set_m[i].x,&node_set_m[i].y);
        for (i=1;i<n;i++)
        {
            len=cal_distance(node_set_n[i],node_set_n[i+1]);
            for (j=1;j<=m;j++)
                if (cal_distance(node_set_n[i],node_set_m[j])+cal_distance(node_set_n[i+1],node_set_m[j])<=2*len)
                    graph[i][j]=true;
        }
        printf("%d\n",n+max_match());
        for (i=1;i<n;i++)
        {
            printf("%d %d ",node_set_n[i].x,node_set_n[i].y);
            if (ans[i]!=-1)
                printf("%d %d ",node_set_m[ans[i]].x,node_set_m[ans[i]].y);
        }
        printf("%d %d\n",node_set_n[n].x,node_set_n[n].y);
    }
    return 0;
}


 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值