poj 1034

二分图最大匹配算法解决遛狗问题
题目的大致意思就是说一个人出去遛狗 狗的速度是人的2倍 狗和人都是从同一点出发 狗会去找骨头之类的东西 人和狗都是直线运动的然后要求在人到达下一点之前狗要到达人的下一个点 求的是狗最多能到达多少个点 并输出.
初看这个题目很容易使人想到计算几何之类的东西 如果不是看分类我真的是想不到会是二分图的最大匹配问题 把人的坐标看成一个集合骨头的坐标看成另一个坐标 这样很明显了 

然后构造二元关系矩阵 最后就是模板般的代码了,另外加了个父亲数组,统计输出的顺序,建图还是很巧妙.

#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 110
int map[N][N],use[N],link[N],n,m;

struct Point
{
	int x,y;
}Bob[N],dog[N];

double  distance(Point a,Point b)
{
	return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
bool chack(int i,int j)  
{
	double s1,s2,s3;
	s1=distance(Bob[i],dog[j]);
	s2=distance(Bob[i+1],dog[j]);
	s3=distance(Bob[i],Bob[i+1]);
	if(s1+s2>2*s3)
		return 0;
	return 1;
}

bool dfs(int x){
    int i,j;    
    for(i=1;i<=m;i++){
        if (use[i]==0&&map[x][i]) {
            use[i]=1;
            j=link[i];
            link[i]=x;
            if (j==-1||dfs(j)) {
                return true;
            }
            link[i]=j;
        }       
    }
    return false;
} 


int hungary(){
	int num=0;
    int i,j;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
			use[j]=0;
		if (dfs(i))
			num++;
	}
	return num;
} 


int main()
{
	int i,j,pre[N];
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%d%d",&Bob[i].x,&Bob[i].y);
        
		for(i=1;i<=m;i++)
            scanf("%d%d",&dog[i].x,&dog[i].y);
		memset(map,0,sizeof(map));
		for(i=1;i<n;i++)
			for(j=1;j<=m;j++)
			{
				if(chack(i,j))
				{
					map[i][j]=1;
				}
			}
			/*
			for(i=1;i<n;i++)
			{
				for(j=1;j<=m;j++)
					printf("%d ",map[i][j]);
				printf("\n");
			}*/
			memset(link,-1,sizeof(link));
			
			printf("%d\n",n+hungary());
			
			/*
			for(i=1;i<=m;i++)
			if(link[i]!=-1)
			printf("%d %d %d\n",i,Bob[link[i]].x,Bob[link[i]].y);
                        */
			
			memset(pre,-1,sizeof(pre));
			for(i=1;i<=m;i++)              
				if(link[i]!=-1)
					pre[link[i]]=i;
				for(i=1;i<n;i++)           //输出
				{
					if(pre[i]==-1)
						printf("%d %d ",Bob[i].x,Bob[i].y);
					else
						printf("%d %d %d %d ",Bob[i].x,Bob[i].y,dog[pre[i]].x,dog[pre[i]].y);
				}
				printf("%d %d",Bob[i].x,Bob[i].y);
				printf("\n");	      
				
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值