原题连接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3209
这个题我想到了用跳舞链,但是我想跳舞链的原理就是搜索,能有多高的效率呢?这个题的数据规模是有500 *30 * 30的,我不知道跳舞链的时间复杂度,随意我犹豫了,但是还是用跳舞链敲了一边,没想到1A,重要的是,以前我一次也没有a掉过一个跳舞链,虽然有模板
解题思路:跳舞链解决的问题是,选择若干的行使得每一列有且仅有一个1,这个题是,选择若干的矩形使得每一个坐标有且仅有一个矩形覆盖
本人还有个疑惑,500*15000的矩阵用跳舞链居然能a了,我想知道,跳舞链到底能解决多大的矩阵?也就是时间复杂度是多少?
具体的看代码吧,我调了好久才对呢
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
#define MAX 0x3f3f3f3f
#define SIZE 100005
bool arr[510][SIZE];
int L[SIZE], R[SIZE], U[SIZE], D[SIZE],Col[SIZE], Row[SIZE]; //这个地方我没有好好的分析每一个数组的具体长度是多少
//所在列 所在行
int S[SIZE];
//列元素数
int sel[SIZE],seln;
//选择的行
int mi;
struct Dancer {
void init(int height,int width)
{
int p/*节点编号*/, x, y, last;
for (p = 1; p <= width; p++)
//初始化列头指针
{
L[p] = p - 1; R[p] = p + 1;
//左右相邻
U[p] = D[p] = p; //只有一列
S[p] = 0; //列元素数
//
}
p = width + 1;
for (y = 1; y <= height; y++) //行
{
last = R[0] = L[0] = 0;//暂作为每行虚拟头指针
for (x = 1; x <= width; x++) //列
{
if (arr[y-1][x-1] != 0) // 0~n-1 -> 1~n !!!!!!!!!!!!!!!
{
//添到行链表尾部
L[p] = last; R[last] = p;
//添到列链表尾部
U[p] = U[x]; D[p] = x; U[x] = D[U[x]] = p;
记录所在行列
Row[p]=y; Col[p]=x;
S[x]++; last=p++;
}
}
// 去虚头,构成行循环链表
R[last] = R[0]; L[R[0]] = last;
}
R[width] = 0;
L[0] = width; R[0] = 1;
S[0] = MAX;
}
//删除c列上所有1元素所在的行
void remove(const int &c)
{
L[R[c]] = L[c]; R[L[c]] = R[c];//经典删除
for (int i = D[c]; i != c; i = D[i])
for (int j = R[i]; j != i; j = R[j])
{
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[Col[j]];
}
}
//恢复c列上所有1元素所在的行
void resume(const int &c)
{
for (int i = U[c]; i != c; i = U[i])
for (int j = L[i]; j != i; j = L[j])
{
U[D[j]] = j;
D[U[j]] = j;
++S[Col[j]];
}
L[R[c]] = c; R[L[c]] = c;//经典恢复
}
bool dance()
{
if (R[0] == 0)
return true;//没有列了
int c=0, i, j;
for (i = R[0]; i != 0; i = R[i])//找元素最少的列c
if (S[i] < S[c]) c = i;
remove(c);
for (i = D[c]; i != c; i = D[i])//删除与c相连的行i
{
for (j = R[i]; j != i; j = R[j])//删除行元素所在的列j
remove(Col[j]);
sel[seln]=Row[i];//选择此行 保存行号
seln++;
if (dance())//对于不同的题,这个地方常常需要改动
{
mi = min(mi,seln);
}
seln--;
for (j = L[i]; j != i; j = L[j])
resume(Col[j]);
}
resume(c);
return false;
}
} dc;
int main()
{
int n,m,p;
int t;
cin >> t;
while(t--)
{
cin >> n >> m >> p;
memset(arr,0,sizeof(arr));
for(int k = 0;k < p;k++)
{
int x1,x2,y1,y2;
cin >> x1 >> y1 >> x2 >> y2;
for(int i = x1;i < x2;i++)
{
for(int j = y1;j < y2;j++)
{
arr[k][i*m+j] = 1;
}
}
}
///
seln=0;
mi = 100000;
dc.init(p,n*m);
dc.dance();
if(mi < 100000)
{
cout << mi << "\n";
}
else
cout << "-1";
putchar('\n');
}
}