【二分图最大匹配】矩阵游戏

矩阵游戏

【问题描述】

       小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:

l       行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)

l       列交换操作:选择矩阵的任意行列,交换这两列(即交换对应格子的颜色)

 

       游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。

       对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。

【输入文件】

       输入文件matrix.in第一行包含一个整数T,表示数据的组数。

       接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。

【输出文件】

       输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。

【样例输入】

       2

       2

       0 0

       0 1

       3

       0 0 1

       0 1 0

       1 0 0

【样例输出】

       No

       Yes

【数据规模】

       对于20%的数据,N ≤ 7

       对于50%的数据,N ≤ 50

       对于100%的数据,N ≤ 200


这是二分图最大匹配,但是我沙茶没有看出来,搜的,过了两个点。。看来这种棋盘模型还是常常要向二分图匹配靠拢。因为同一行的纵向移动不会影响一行的情况,同一列的横向移动不会影响一列的情况。能够看出来,一行一列相交确定一个点,我们通过一些移动,把它移动到(1,1)或(2,2)........,一个行和一个列都只能用一次,因此只要能找到n个匹配就表示能够移动到主对角线上


另外,清空标志数组不要在匈牙利模块里面进行,这样可能会死循环。


#include <cstring>
#include <cstdio>

struct node
{
	long ind;
	node* nxt;	
};
node* head[210];
long lnk[210];
bool vis[210];

void insert(long a,long b)
{
	node* tmp = new node;
	tmp -> ind = b;
	tmp -> nxt = head[a];
	head[a] = tmp;	
}

bool Hungary(long u)
{
	for (node* vv=head[u];vv;vv=vv->nxt)
	{
		long v = vv->ind;
		if (!vis[v])
		{
			vis[v] = true;
			if (!lnk[v] || Hungary(lnk[v]))
			{
				lnk[v] = u;
				return true;;
			}
		}
	}
	return false;
}

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	
	long T;
	scanf("%ld",&T);
	long n=0;	
	while (T--)
	{
		
		for (long i=1;i<n+1;i++)
		{
			head[i] = 0;
			lnk[i] = 0;
		}
//		memset(head,0,sizeof head);
//		memset(lnk,0,sizeof lnk);
		long _cnt1 = 0;
		scanf("%ld",&n);
		for (long i=1;i<n+1;i++)
		{
			for (long j=1;j<n+1;j++)
			{
				getchar();
				char tmp = getchar()-'0';
				_cnt1 += tmp;
				if (tmp)
					insert(i,j);
			}
		}
		if (_cnt1 < n)
		{
			printf("No\n");
			continue;
		}
			
		for (long i=1;i<n+1;i++)
		{
			memset(vis,0,sizeof(vis));
			Hungary(i);
		}
		long ans = 0;
		for (long i=1;i<n+1;i++)
		{
			ans += bool(lnk[i]);
		}
		if (ans >= n)
			printf("Yes\n");
		else
			printf("No\n");
	}
	return 0;
}

再贴一个暴搜

#include <cstdio>

bool flag = false;
long count1 = 0;
long T;long n;
bool hash1[210];
bool hash2[210];

struct node
{
	long x;
	long y;	
};
node point[40010];
long used;

void dfs(long u)
{
	if (count1-u+1+used < n)
	{
		return;
	}
	if (u == count1+1)
	{
		bool can = true;
		for (long i=1;i<n+1;i++)
		{
			can &= hash1[i];
			can &= hash2[i];
			if (!can)
				return;
		}
		flag = true;
		return;
	}
	int tmp1 = hash1[point[u].x];
	int tmp2 = hash2[point[u].y];
	if (tmp1+tmp2==0)
		hash1[point[u].x] = hash2[point[u].y] = true;
	used++;
	dfs(u+1);
	used--;
	hash1[point[u].x] = tmp1;
	hash2[point[u].y] = tmp2;
	if (flag) return;
	dfs(u+1);
}

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	
	scanf("%ld",&T);
	while (T--)
	{
		count1 = 0;
		used = 0;
		scanf("%ld",&n);
		for (long i=1;i<n+1;i++)
		{			
			for (long j=1;j<n+1;j++)
			{
				getchar();
				char tmp = getchar() - '0';
				if (tmp)
				{
					++count1;
					point[count1].x = i;
					point[count1].y = j;
				}
			}
		}
		if (count1 < n)
		{
			printf("No\n");	
			continue;
		}
		flag = false;
		dfs(1);
		if (flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值