参考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;
}