需要注意的有:
(1)行和列,斜線的hash
(2)搜的時候只用搜行或列即可
(3)成功條件:d >=n
(4)注意初始化!!!
???爲什麼白書的模板TLE???
網上模板ac:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxnode = 55 * 55 * 4;
const int maxr = 55 * 55;
const int maxc = 55 * 6;
int U[maxnode],D[maxnode],L[maxnode],R[maxnode],C[maxnode],row[maxnode];
int H[maxr],S[maxc];
int ansd, ans[maxr];/// 注意初始化
int n,sz;
void init(int r,int c)
{
for(int i=0; i<=c; ++i)
{
S[i]=0;
U[i]=D[i]=i;
L[i+1]=i;
R[i]=i+1;
}
R[sz=c]=0;
while(r)H[r--]=-1;
}
void remove(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[C[j]];
}
void resume(int c)
{
L[R[c]]=R[L[c]]=c;
for(int i=U[c]; i!=c; i=U[i])
for(int j=L[i]; j!=i; j=L[j])
++S[C[U[D[j]]=D[U[j]]=j]];
}
bool Dance(int d)
{
if(d>=n)
{
ansd = d;
return 1;
}
if(!R[0])return 0;
int c,tmp=maxnode;
for(int i=R[0]; i; i=R[i])
if(i<=n)
{
if(S[i]<tmp)tmp=S[c=i];
}
else break;
remove(c);
for(int i=D[c]; i!=c; i=D[i])
{
ans[d] = row[i];
for(int j=R[i]; j!=i; j=R[j])remove(C[j]);
if(Dance(d+1))return 1;
for(int j=L[i]; j!=i; j=L[j])resume(C[j]);
}
resume(c);
return 0;
}
void Link(int r,int c)
{
++S[C[++sz]=c];
row[sz]=r;
D[sz]=D[c];
U[D[c]]=sz;
U[sz]=c;
D[c]=sz;
if(H[r]<0)H[r]=L[sz]=R[sz]=sz;
else
{
R[sz]=R[H[r]];
L[R[H[r]]]=sz;
L[sz]=H[r];
R[H[r]]=sz;
}
}
void place(int &p1,int &p2,int &p3,int &p4,int i,int j)
{
p1=j,p2=n+i,p3=n+n+i-j+n,p4=n+n+n+n-1+i+j-1;
}
bool p[maxnode];
int a[55];
int main()
{
int i,j,k,p1,p2,p3,p4;
while(scanf("%d",&n)!=-1)
{
for(i=1; i<=n*6-2; ++i)p[i]=0;
init(n*n,n*6-2);
for(k=i=1; i<=n; ++i)
{
scanf("%d",&j);
if(j)
{
place(p1,p2,p3,p4,i,j);
p[p1]=p[p2]=p[p3]=p[p4]=1;
Link((i - 1) * n + j,p1),Link((i - 1) * n + j,p2),Link((i - 1) * n + j,p3),Link((i - 1) * n + j,p4);
}
}
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j)
{
place(p1,p2,p3,p4,i,j);
if(p[p1]||p[p2]||p[p3]||p[p4])continue;
Link((i - 1) * n + j,p1),Link((i - 1) * n + j,p2),Link((i - 1) * n + j,p3),Link((i - 1) * n + j,p4);
}
Dance(0);
for (int i = 0; i < ansd; i++)
{
int val = ans[i];
int x = (--val) / n;
int y = val % n;
x++;
y++;
a[x] = y;
}
for (int i = 1; i <= n; i++)
{
if (i != 1) printf(" ");
printf("%d", a[i]);
}
puts("");
}
return 0;
}
白書模板TLE:(???????)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int maxnode = 55 * 55 * 4;
const int maxr = 55 * 55;
const int maxc = 55 * 6;
int N;
///精確區間覆蓋
///行編號從1開始,列編號爲1~c,結點0爲表頭結點
///注意給行和列的編號
///注意sz,ans.要自己初始化和賦值!!!
struct DLX
{
int n , sz; // 每列的行數,節點總數
int S[maxc]; // 各列節點總數
int row[maxnode],col[maxnode]; // 各節點行列編號
int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字鏈表
int ansd, ans[maxr]; // 解,行數
void init(int n )
{
this->n = n ;
for(int i = 0 ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - 1;
R[i] = i + 1;
}
R[n] = 0 ;
L[0] = n;
sz = n + 1 ;
memset(S,0,sizeof(S));
}
void addRow(int r,vector<int> c1)
{
int first = sz;
for(int i = 0 ; i < c1.size(); i++ )
{
int c = c1[i];
L[sz] = sz - 1 ;
R[sz] = sz + 1 ;
D[sz] = c ;
U[sz] = U[c];
D[U[c]] = sz;
U[c] = sz;
row[sz] = r;
col[sz] = c;
S[c] ++ ;
sz ++ ;
}
R[sz - 1] = first ;
L[first] = sz - 1;
}
// 順着鏈表A,遍歷除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i])
void remove(int c)
{
L[R[c]] = L[c];
R[L[c]] = R[c];
FOR(i,D,c)
FOR(j,R,i)
{
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[col[j]];
}
}
void restore(int c)
{
FOR(i,U,c)
FOR(j,L,i)
{
++S[col[j]];
U[D[j]] = j;
D[U[j]] = j;
}
L[R[c]] = c;
R[L[c]] = c;
}
bool dfs(int d)
{
if (d >= N)
{
ansd = d;
return true;
}
if (!R[0]) return false;///!!!
// 找S最小的列c
int c = R[0], tmp = S[R[0]];
FOR(i, R, 0)
if (i <= N) if (S[i] < tmp) tmp = S[c = i];///斜線部分不遍歷
else break;
remove(c);
FOR(i,D,c)
{
ans[d] = row[i];
FOR(j,R,i) remove(col[j]);
if(dfs(d + 1)) return true;
FOR(j,L,i) restore(col[j]);
}
restore(c);
return false;
}
bool solve(vector<int> & v)
{
v.clear();
if(!dfs(0)) return false;
for(int i = 0 ; i< ansd ; i ++ ) v.push_back(ans[i]);
return true;
}
};
DLX solver;
void decode(int val, int &x, int &y)
{
val--;
x = val / N;
y = val % N;
x++;
y++;
}
vector<int>v;
bool p[55 * 55 * 4];
void place(int &p1,int &p2,int &p3,int &p4,int i,int j)
{
p1=j,p2=N+i,p3=N+N+i-j+N,p4=N+N+N+N-1+i+j-1;
}
int main()
{
int a[55];
while (cin >> N)
{
memset(p, 0, sizeof(p));
solver.init(6 * N - 2);
for (int i = 1; i <= N; i++)
{
scanf("%d", &a[i]);
if (!a[i]) continue;
int p1, p2, p3, p4;
place(p1, p2, p3, p4, i, a[i]);
v.clear();
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
p[p1] = p[p2] = p[p3] = p[p4] = 1;
solver.addRow((i - 1) * N + a[i], v);
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
int p1, p2, p3, p4;
place(p1, p2, p3, p4, i, j);
if (p[p1] || p[p2] || p[p3] || p[p4]) continue;
v.clear();
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
solver.addRow((i - 1) * N + j, v);
}
}
v.clear();
solver.solve(v);
for (int i = 0; i < v.size(); i++)
{
int x, y;
decode(v[i], x, y);
a[x] = y;
}
for (int i = 1; i <= N; i++)
{
if (i != 1) printf(" ");
printf("%d", a[i]);
}
puts("");
}
return 0;
}