POJ 1636 Prison rearrangement

传送门:http://poj.org/problem?id=1636


有两个监狱,两个监狱之间的人有的不能在一起,否则会摔♂跤。现在要交换两个监狱中的某些人,使两边人数依然相同,求最多交换的人数(ans=n/2)


我们需要求的是如何在两边选出相同的人数,对于不能在一起的人,必须同时移动,所以可以按给定的关系建边,连通的人要同时移动。此时每一组人,左边的人数为a[i],

右边的人数为b[i],在取的时候相当于背包dp


开始的时候忘了初始化a[],b[]。。。


代码如下:

#include<cstdio>
#include<cstring>

using namespace std;

struct edge
{
	int y,next;
};

	edge v[40005];
	bool f[405];
	int head[405];
	int a[200];
	int b[200];
	bool dp[205][205];	
	int tot;
	int n,m;
	int T;
	int ans;
	
void add(int x,int y)
{
	tot++;
	v[tot].y=y;
	v[tot].next=head[x];
	head[x]=tot;
}
	
void dfs(int now)
{
	f[now]=1;
	if (now<=n)
	{
		a[tot]++;
	}
	else
	{
		b[tot]++;
	}
	for (int x=head[now];x;x=v[x].next)
	{
		if (!f[v[x].y])
		{
			dfs(v[x].y);
		}
	}
}
	
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d%d",&n,&m);
		memset(head,0,sizeof(head));
		int x,y;
		tot=0;
		for (int i=1;i<=m;i++)
		{
			scanf("%d%d",&x,&y);
			add(x,y+n);
			add(y+n,x);
		}
		
		memset(f,0,sizeof(f));
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		tot=0;
		for (int i=1;i<=n+n;i++)
		{
			if (!f[i])
			{
				tot++;
				dfs(i);
			}
		}
		
		memset(dp,0,sizeof(dp));
		dp[0][0]=1;
		for (int i=1;i<=tot;i++)
		{
			for (int j=n/2;j>=a[i];j--)
			{
				for (int k=n/2;k>=b[i];k--)
				{
					if (dp[j-a[i]][k-b[i]])
					{
						dp[j][k]=1;
					}	
				}
			}
		}
		
		ans=n/2;
		while (!dp[ans][ans])
		{
			ans--;
		}
		printf("%d\n",ans);
	}
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值