poj3057(经典二分匹配)

解题思路:本来这道题可以用二分来做,更加直观一些。但是挑战上又介绍了优化的方法,所以试了一下。一些重要的细节代码里注释了。大概思路这里讲一下:就是随着时间的增加来添加点(不同时刻的门)和边。然后添加的新的时刻的门去和人进行匹配,如果匹配上了就代表在这个时刻这扇门可以送走一个人。随着时间的增加,新时刻的门继续把剩余的人给匹配掉。直至全部人匹配完,或者时间到为止。这里的时间最长是n*m,即输入矩阵的大小。因为假使只有一扇门,其余位置全是人,那n*m的时间也可以把人都给送出去了。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node
{
	int x,y;
	node(int x,int y):x(x),y(y){}
	node(){
	}
};
char s[13][13],n,m;
int dis[13][13][13][13],match[50009],chk[50009];
int dx[4]={-1,0,0,1},dy[4]={0,1,-1,0};
vector<node> p1,p2;
vector<int> g[50008];
void bfs(int x,int y,int d[13][13])
{
	queue<node> q;
	node t;
	d[x][y]=0;
	q.push(node(x,y));
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		for(int k=0;k<4;k++)
		{
			int tx=t.x+dx[k];
			int ty=t.y+dy[k];
			if(tx>=0&&tx<n&&ty>=0&&ty<m&&s[tx][ty]=='.'&&d[tx][ty]<0)
			{
				d[tx][ty]=d[t.x][t.y]+1;
				q.push(node(tx,ty));
			}
		}		
	}
}
void add_edge(int u,int v)
{
	g[u].push_back(v);
}
int dfs(int u)
{
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(!chk[v])
		{
			chk[v]=1;
			int t=match[v];
			match[v]=u;
			if(t==-1||dfs(t))
			return 1;
			match[v]=t;
		}
	}
	return 0;
}
void solve()
{
	int t1=p1.size(),t2=p2.size();
	if(t2==0)
	{
		printf("0\n");
		return;
	}
	for(int i=0;i<t1;i++)
	{
		for(int j=0;j<t2;j++)
		{
			if(dis[p1[i].x][p1[i].y][p2[j].x][p2[j].y]>0)//这一步必须有,不然那些与世隔绝的人的-1会造成内存错位 
			for(int k=dis[p1[i].x][p1[i].y][p2[j].x][p2[j].y];k<=n*m;k++)
			{
				add_edge((k-1)*t1+i,n*m*t1+j);//(k-1)*t1+i表示第k时刻第i个门 , n*m*t1+j代表第j个人。
				//这里的意思是第j个人不考虑拥堵时是可以从k时刻第i个门出去的。 
			}
		}
	}
//以下是经典的匈牙利算法 
	memset(match,-1,sizeof(match));
	int num=0;
	for(int v=0;v<n*m*t1;v++)
	{
		memset(chk,0,sizeof(chk));
		if(dfs(v))
		{
			num++;
			if(num==t2)
			{
				printf("%d\n",v/t1+1);
				return;
			}
		}
	}
	printf("impossible\n");
}
int main()
{
	//freopen("t.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		getchar();
		for(int i=0;i<n;i++)
		{
			gets(s[i]);
			//printf("%s\n",s[i]);
		}
		p1.clear();
		p2.clear();
		memset(dis,-1,sizeof(dis));
		for(int i=0;i<50008;i++) g[i].clear();
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(s[i][j]=='D')
				{
					p1.push_back(node(i,j));
					bfs(i,j,dis[i][j]);
				}else
				if(s[i][j]=='.')
				{
					p2.push_back(node(i,j));
				}
			}
		}		
		solve();
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_39861441/article/details/87653926