跳舞链

参考http://hihocoder.com/contest/hiho101/problem/1

小Ho最近遇到一个难题,他需要破解一个棋局。

棋局分成了n行,m列,每行有若干个棋子。小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子。

比如下面这样局面:

其中1表示放置有棋子的格子,0表示没有放置棋子。

输入

第1行:1个正整数t,表示数据组数,1≤t≤10。

接下来t组数据,每组的格式为:

第1行:2个正整数n,m,表示输入数据的行数和列数。2≤n,m≤100。

第2..n+1行:每行m个数,只会出现0或1。

输出

第1..t行:第i行表示第i组数据是否存在解,若存在输出"Yes",否则输出"No"。

样例输入
2
4 4
1 1 0 1
0 1 1 0
1 0 0 0
0 1 0 1
4 4
1 0 1 0
0 1 0 0
1 0 0 0
0 0 1 1
样例输出
No
Yes

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <cmath>
#define maxn 100005
#define INF 1000000000
using namespace std;
typedef long long ll;

struct Node{
	Node(){
	}
	Node(int a, int b, int c, int d, int f, int g, int h){
		Left = a;
		Right = b;
		Up = c;
		Down = d;
		x = f;
		y = g; 
		i = h;
	}
	int Left, Right, Up, Down;
	int x, y, i;
}node[10005];
int n, m, cnt;
int vis[105][105], id[105][105], ans[105];
void Build(){
	 
	cnt = 0;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	  for(int j = 1; j <= m; j++)
	   scanf("%d", &vis[i][j]);
    node[0] = Node(0, 0, 0, 0, 0, 0, 0);
	Node* pre = &node[0];
	for(int i = 1; i <= m; i++){
		node[i] = Node(i, i, i, i, 0, i, i);
		Node *p = node + i;
	    p -> Right = pre -> Right;
	    p -> Left = pre -> i;
	    node[pre -> Right].Left = p -> i;
	    pre -> Right = p -> i;
	    pre = p;
	}
	cnt = m;
	for(int i = 1; i <= n; i++)
	  for(int j = 1; j <= m; j++){
	  	if(vis[i][j] == 1){
	  	  id[i][j] = ++cnt;
	  	  node[cnt] = Node(cnt, cnt, cnt, cnt, i, j, cnt);
	     }
	  }
	for(int i = 1; i <= m; i++){
		Node *pre = &node[i];
		for(int j = 1; j <= n; j++){
		    if(vis[j][i] == 0)
		      continue;
		    Node *p = &node[id[j][i]];
		    p -> Down = pre -> Down;
		    p -> Up = pre -> i;
		    node[pre -> Down].Up = p -> i;
		    pre -> Down = p -> i;
		    pre = p;
		}
	}
	for(int i = 1; i <= n; i++){
		Node *pre = NULL;
		for(int j = 1; j <= m; j++){
			if(vis[i][j] == 0)
			 continue;
			if(pre == NULL){
				pre = &node[id[i][j]];
			} 
			else{
				Node *p = &node[id[i][j]];
				p -> Right = pre -> Right;
			    p -> Left = pre -> i;
			    node[pre -> Right].Left = p -> i;
			    pre -> Right = p -> i;
			    pre = p;
			}
		}
	}
}
void Remove(int col){
	
	node[node[col].Left].Right = node[col].Right;
	node[node[col].Right].Left = node[col].Left;
	Node p = node[node[col].Down];
	while(p.i != node[col].i){
		
		Node h = node[p.Right];
		while(p.i != h.i){
			node[h.Up].Down = h.Down;
			node[h.Down].Up = h.Up;
			h = node[h.Right];
		}
		p = node[p.Down];
	}
}
void Rescume(int col){
	
	node[node[col].Left].Right = node[col].i;
	node[node[col].Right].Left = node[col].i;
	Node p = node[node[col].Down];
	while(p.i != node[col].i){
		
		Node h = node[p.Right];
		while(p.i != h.i){
			node[h.Up].Down = h.i;
			node[h.Down].Up = h.i;
			h = node[h.Right];
		}
		p = node[p.Down];
	}
}
bool Dance(int depth){
	
	Node p = node[node[0].Right];
	if(p.i == node[0].i)
	  return true;
	if(p.Down == p.i)
	  return false;
	
	Node p2 = node[p.Down];
	Remove(p.y);
	while(p2.i != p.i){
		
		Node h = node[p2.Right];
		ans[depth] = h.x;
		while(h.i != p2.i){
			Remove(h.y);
			h = node[h.Right];
		}
		if(Dance(depth + 1))
		  return true;
		h = node[p2.Left];
		while(h.i != p2.i){
			Rescume(h.y);
			h = node[h.Left];
		}
		p2 = node[p2.Down];
	}
	Rescume(p.y);
	return false;
}
int main(){
	
//	freopen("in.txt", "r", stdin);
	int t;
	
	scanf("%d", &t);
	while(t--){
		
		Build();
		if(Dance(0))
		  puts("Yes");
		else
		  puts("No");
		   
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值