题目链接:http://hihocoder.com/problemset/problem/1317
题意:
小Ho最近遇到一个难题,他需要破解一个棋局。
棋局分成了n行,m列,每行有若干个棋子。小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子。
来一个链接好复习https://www.cnblogs.com/grenet/p/3145800.html
跳舞链模板
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
const int maxm=105;
const int maxnode=105*105;
const int head=0;
typedef long long ll;
int L[maxnode],R[maxnode],U[maxnode],D[maxnode],Row[maxnode];
int C[maxnode],H[maxnode],coln[maxm],ans[maxn],vis[maxn];
int n,m,sz,len;
void init(){
for(int i=0;i<=m;i++){
coln[i]=0; U[i]=D[i]=i;
L[i+1]=i;R[i]=i+1;
}
R[m]=0; L[0]=m;
memset(H,-1,sizeof(H));
sz=m+1;
}
void addLink(int r,int c){
coln[c]++; C[sz]=c; Row[sz]=r;
U[sz]=U[c]; D[U[c]]=sz;
D[sz]=c; U[c]=sz;
if(H[r]==-1) H[r]=L[sz]=R[sz]=sz;
else{
L[sz]=L[H[r]]; R[L[sz]]=sz;
R[sz]=H[r]; L[H[r]]=sz;
}
sz++;
}
void Remove(int sz){
L[R[sz]]=L[sz]; R[L[sz]]=R[sz];
for(int i=D[sz];i!=sz;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
U[D[j]]=U[j]; D[U[j]]=D[j];
coln[C[j]]--;
}
}
}
void Resume(int sz){
for(int i=D[sz];i!=sz;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
U[D[j]]=j; D[U[j]]=j;
coln[C[j]]++;
}
}
L[R[sz]]=sz; R[L[sz]]=sz;
}
int DLX(int k){
//如果head的右边也是head 说明已经删除完毕
if(R[head]==head){
len=k;
return 1;
}
int minn=maxn,minpos=-1;
//找到当前还有1的数量最少的列进行选择 算是个优化了
for(int i=R[0];i!=0;i=R[i]){
if(minn>coln[i]){
minn=coln[i]; minpos=i;
}
}
Remove(minpos);
//选择要删去的行并实时更新至ans中
for(int i=D[minpos];i!=minpos;i=D[i]){
ans[k]=Row[i];
for(int j=R[i];j!=i;j=R[j]) {
//选择点i所在的行作为覆盖c列的行
//要删掉该行所覆盖的列
Remove(C[j]);
}
if(DLX(k+1)) return 1;
for(int j=L[i];j!=i;j=L[j]) Resume(C[j]);
}
Resume(minpos);
return 0;
}
int main(){
int T; cin>>T;
while(T--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int xx; scanf("%d",&xx);
if(xx) addLink(i,j);
}
}
int ans=DLX(0);
if(ans) printf("Yes\n");
else printf("No\n");
}
return 0;
}