现在的位置: 首页 > 综合 > 正文

二分图水题整理 Poj 2060 + 1466 + 2771 + hdu 1150 + 1151

2014年02月17日 ⁄ 综合 ⁄ 共 4782字 ⁄ 字号 评论关闭

Poj 2060 Taxi Cab Scheme

题意:在一个矩形城市里面,有间出租车公司收到翌日的预订行程M个,每个给出起点、终点坐标,两个地点之间的车程就是那两个点之间的曼哈顿距离,车起码要在一个行程的出发时间前一分钟到起点。求最少要多少出租车才够完成所有预订?

分析:记A,B是两个行程的起点,A',B'分别是终点,假如由A'到B的时间还在B的规定时间前,那么要走完AA',BB'要用的出租车就只需要一台。添加一条有向边<A',B>,把图建好之后,求出最小路径覆盖就是答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;

const int N=505;
bool map[N][N];
bool vis[N];
int match[N];
int m;

bool Dfs (int u)
{
	for (int v=1;v<=m;v++)
		if (vis[v] == false && map[u][v])
		{
			vis[v]=true;
			if (match[v]==0 || Dfs(match[v]))
			{
				match[v]=u;
				return true;
			}
		}
	return false;
}


struct Point
{
	int st,et;
	int sx,sy,ex,ey,dis,len;
	void Get ()
	{
		scanf("%d:%d %d%d%d%d",&st,&et,&sx,&sy,&ex,&ey);
		sx++,sy++,ex++,ey++;
		st=st*60+et;
		dis=abs(sx-ex)+abs(sy-ey);
		et=st+dis;
	}
	bool Cal (const Point& b) const
	{
		int d=abs(ex-b.sx)+abs(ey-b.sy);
		if (d+et<b.st)    //严格小于,<=,WA
			return true;
		return false;
	}
}data[N];

int main ()
{
	int T;
	scanf("%d",&T);
	for (int Cas=1;Cas<=T;Cas++)
	{
		memset(map,false,sizeof(map));
		memset(match,0,sizeof(match));
		scanf("%d",&m);
		int i,sum;
		for (i=1;i<=m;i++)
			data[i].Get();
		/*求最大匹配*/
		for (i=1;i<m;i++)
			for (int j=i+1;j<=m;j++)
			{
				if (data[i].Cal(data[j]))
					map[i][j]=true;
			}
		for (sum=0,i=1;i<=m;i++)
		{
			memset(vis,false,sizeof(vis));
			if (Dfs(i))
				sum++;
		}
		printf("%d\n",m-sum);
	}
	return 0;
}

Poj 1466 Girls and Boys

题意:一些人开始研究一种浪漫的关系,这种浪漫的关系被定义在一个男孩和一个女孩之间。
这项研究给出了,每个学生的该种关系列表已经给出,但他们想知道满足下面条件集合元素的最大个数是多少:该集合中任意两个人都没有上述关系。
思路:如果将有这种关系的两个人用边连起来,那么最终要求的集合中两两无边,对应图论中最大独立集。
最大独立集= n - 最小点覆盖。 最小点覆盖 = 二分图最大匹配。
将每个人拆成两个点,a,b 有关系,就连一条a ->b的有向边。由于在寻找最大匹配时不是枚举其中一边的点,而是枚举两边的所有点,所以得到的ans为最大匹配数的两倍,因为每条匹配的边都算了两遍。

也就是说最终的匹配数应该是该图最大匹配的1/2.那么答案就出来了。

#include <cstdio>
#include <cstring>

const int N=505;
bool map[N][N];
bool vis[N];
int match[N];
int n,num;

bool Dfs (int u)
{
	for (int v=0;v<n;v++)
		if (vis[v] == false && map[u][v])
		{
			vis[v]=true;
			if (match[v]==-1 || Dfs(match[v]))
			{
				match[v]=u;
				return true;
			}
		}
	return false;
}

void Input ()
{
	int i,T,u,v;
	num=0;
	memset(map,false,sizeof(map));
	memset(match,-1,sizeof(match));
	for (i=0;i<n;i++)
	{
		scanf("%d: (%d)",&u,&T);
		while (T--)
		{
			scanf("%d",&v);
			map[u][v]=true;
		}
	}
}

int main ()
{
	while (~scanf("%d",&n))
	{
		Input ();
		for (int i=0;i<n;i++)
		{
			memset(vis,false,sizeof(vis));
			if (Dfs(i))
				num++;
		}
		printf("%d\n",n-num/2);
	}
	return 0;
}

Poj 2771 Guardian of Decency

题意:人和人之间如果满足4个条件的任意一条就不会成为夫妻,给定一些人,问从中最多能选多少人且保证任意两人不可能成为夫妻。
分析:由于条件之一是性别相同则不能成为夫妻。我们根据性别把人划分为两个集合,每个人是一个结点构成二分图,若两个人可能成为夫妻则连一条边。(同性之间不能成为夫妻,所以同集合内无边,此图必定为二分图)。题目要求是选出最多的人,且任意两人之间无边。这就是求二分图的最大独立集。只要用总人数-最大匹配数即可。

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

const int N=505;
bool map[N][N];
bool vis[N];
int match[N];
int n,num,m,f;

struct Point
{
	int h;
	char m[105],s[105];
}male[N],female[N];

bool Dfs (int u)
{
	for (int v=1;v<=f;v++)
		if (vis[v] == false && map[u][v])
		{
			vis[v]=true;
			if (match[v]==-1 || Dfs(match[v]))
			{
				match[v]=u;
				return true;
			}
		}
	return false;
}

bool Judge (Point a,Point b)
{
	if (fabs(a.h-b.h)>40)
		return false;
	if (strcmp(a.m,b.m))
		return false;
	if (strcmp(a.s,b.s)==0)
		return false;
	return true;
}

void Input ()
{
	int i,a;
	char s[5];
	memset(map,false,sizeof(map));
	memset(match,-1,sizeof(match));
	for (i=1;i<=n;i++)
	{
		scanf("%d%s",&a,s);
		if (s[0]=='M')
		{
			male[++m].h=a;
			scanf("%s%s",male[m].m,male[m].s);
		}
		else
		{
			female[++f].h=a;
			scanf("%s%s",female[f].m,female[f].s);
		}
	}
	for (i=1;i<=m;i++)
		for (int j=1;j<=f;j++)
		{
			if (Judge(male[i],female[j]))
				map[i][j]=true;
		}

}

int main ()
{
#ifdef ONLINE_JUDGE
#else
	freopen("read.txt","r",stdin);
#endif
	int T;
	scanf("%d",&T);
	for (int Cas=1;Cas<=T;Cas++)
	{
		scanf("%d",&n);
		num=m=f=0;
		Input ();
		for (int i=1;i<=m;i++)
		{
			memset(vis,false,sizeof(vis));
			if (Dfs(i))
				num++;
		}
		printf("%d\n",n-num);
	}
	return 0;
}


hdu 1150 Machine Schedule


题意:机器调度问题,有两台机器,分别有n和m种工作状态,现有k个任务,需要用这两种机器来完成,由于每更换一次机器的工作状态都需重启,怎样安排这些任务,使得机器的重启次数最少

思路:由于每个任务都可以用A或B机器的某种工作状态来完成,因此,对于每个任务,

可以把A,B的工作状态作为顶点,在对应的A和B的工作状态间连线,则对于每条边的两个顶点,
因为每个任务都要完成,故至少要有一个顶点(某个机器的一种状态)存在,
这样这个问题就转化成了在这些顶点中选取尽量少的顶点(尽量少的工作状态,尽量少的重启次数),
使得每一条边都至少和其中一个点相关联,即最小点覆盖问题。二分图的最小点覆盖数=最大匹配数

#include <iostream>
using namespace std;

const int N=105;
bool map[N][N];
bool vis[N];
int match[N];
int n,m,k;

bool Dfs (int u)
{
	for (int v=1;v<=m;v++)
		if (vis[v] == false && map[u][v])
		{
			vis[v]=true;
			if (match[v]==0 || Dfs(match[v]))
			{
				match[v]=u;
				return true;
			}
		}
	return false;
}

int main ()
{
	while (scanf("%d",&n),n)
	{
		scanf("%d%d",&m,&k);
		memset(map,false,sizeof(map));
		memset(match,0,sizeof(match));
		int i,a,b,sum;
		for (i=1;i<=k;i++)
		{
			scanf("%*d%d%d",&a,&b);
			if (a==0 || b==0)   //初始状态为0,不用记录在改变次数中
				continue;
			map[a+1][b+1]=true;
		}
		/*求最大匹配*/
		for (sum=0,i=1;i<=n;i++)
		{
			memset(vis,false,sizeof(vis));
			if (Dfs(i))
				sum++;
		}
		printf("%d\n",sum);
	}
	return 0;
}

Hdu 1151 Air Raid

最小边覆盖=N-二分图最大匹配

#include <stdio.h>
#include <string.h>

const int N=125;
bool map[N][N];
bool vis[N];
int match[N];
int ni,ns;

bool DFS (int u)
{
    for (int v=1;v<=ni;v++)
        if (vis[v] == false && map[u][v])
        {
            vis[v]=true;
            if (match[v]==0 || DFS(match[v]))
            {
                match[v]=u;
                return true;
            }
        }
    return false;
}

int main()
{
    int T,i,temp1,temp2,ans;
    scanf("%d",&T);
    while (T--)
    {
        ans=0;
        memset(map,false,sizeof(map));
        memset(match,0,sizeof(match));
        scanf("%d%d",&ni,&ns);
        for (i=1;i<=ns;i++)
        {
            scanf("%d%d",&temp1,&temp2);
            map[temp1][temp2]=true;
        }
        for (i=1;i<=ni;i++)
        {
            memset(vis,false,sizeof(vis));
            if (DFS(i))
                ans++;
        }
        printf("%d\n",ni-ans);
    }
    return 0;
}

抱歉!评论已关闭.