SPOJ 1771&&DLX精確覆蓋,重複覆蓋

來源:互聯網
上載者:User

標籤:blog   http   os   io   for   ar   art   問題   div   

DLX的題,做過這題才算是會吧。

這道題轉化成了精確覆蓋模型來做,一開始,只是單純的要覆蓋完行列和斜線,WA。

後來醒悟了,不能這樣,只要覆蓋全部行或列即可。雖然如此,但某些細節地方很關鍵不能考慮到。

特別要注意的是

for(int i=R[c];i;i=R[i]){ if(i>ne) break; if(S[i] < S[c]) c = i;}

找最小值只能是在ne之前,為什麼呢?因為我們要完全覆蓋行。可行嗎?可行。稍微留意一下DLX的模板就知道,它其實在選中一列之後,是會枚舉列上的行值,

也就是說,該列(代表棋盤某一行)的每一個們置都會考慮到,不必擔心無解。

DLX這個演算法很巧妙啊,其實它只是一種高效的剪枝吧。妙妙妙,做過這題後才算真正懂得這個演算法。

#include<cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn=500;const int maxnode=500*2500;int ne;int anst[maxn];struct DLX{  int n , sz;                                                 // 行數,節點總數  int S[maxn];                                                // 各列節點總數  int row[maxnode],col[maxnode];                              // 各節點行列編號  int L[maxnode],R[maxnode],U[maxnode],D[maxnode];            // 十字鏈表  int ansd,ans[maxn];                                         // 解  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 >= ne ){      ansd=d;      for(int i=0;i<ne;i++){      int x=(ans[i]-1)/ne+1;      int y=(ans[i]-1)%ne+1;      anst[x]=y;      }      printf("%d",anst[1]);      for(int i=2;i<=ne;i++)      printf(" %d",anst[i]);      printf("\n");      return true;    }    // 找S最小的列c    int c = R[0] ;    for(int i=R[c];i;i=R[i]){ if(i>ne) break; if(S[i] < S[c]) c = i;}    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;  }  void solve(){    dfs(0);  }};DLX solver;int puzzle[100][100];int main(){int tmp;while(scanf("%d",&ne)!=EOF){memset(puzzle,0,sizeof(puzzle));for(int k=1;k<=ne;k++){scanf("%d",&tmp);if(tmp>0){for(int i=1;i<=ne;i++)puzzle[k][i]=puzzle[i][tmp]=-1;for(int i=1;k-i>0&&tmp-i>0;i++)puzzle[k-i][tmp-i]=-1;for(int i=1;k+i<=ne&&tmp+i<=ne;i++)puzzle[k+i][tmp+i]=-1;for(int i=1;k-i>0&&tmp+i<=ne;i++)puzzle[k-i][tmp+i]=-1;for(int i=1;k+i<=ne&&tmp-i>0;i++)puzzle[k+i][tmp-i]=-1;puzzle[k][tmp]=1;}}solver.init(6*ne-2);vector<int>columns;for(int i=1;i<=ne;i++){for(int j=1;j<=ne;j++){columns.clear();if(puzzle[i][j]>=0){columns.push_back(i);columns.push_back(ne+j);columns.push_back(ne*2+j-1+i);columns.push_back(ne*2+2*ne-1+ne-i+j);solver.addRow((i-1)*ne+j,columns);}}}solver.solve();}return 0;}

  

 

摘http://www.cnblogs.com/jh818012/p/3252154.html

重複覆蓋模板

const int maxn=360000;const int maxc=500;const int maxr=500;const int inf=0x3f3f3f3f;int L[maxn], R[maxn], D[maxn], U[maxn], C[maxn];int S[maxc], H[maxr], size;///不需要S域void Link(int r, int c){    S[c]++; C[size]=c;    U[size]=U[c]; D[U[c]]=size;    D[size]=c; U[c]=size;    if(H[r]==-1) H[r]=L[size]=R[size]=size;    else {        L[size]=L[H[r]]; R[L[H[r]]]=size;        R[size]=H[r]; L[H[r]]=size;    }    size++;}void remove(int c){    for (int i=D[c]; i!=c; i=D[i])        L[R[i]]=L[i], R[L[i]]=R[i];}void resume(int c){    for (int i=U[c]; i!=c; i=U[i])        L[R[i]]=R[L[i]]=i;}int h(){///用精確覆蓋去估算剪枝    int ret=0;    bool vis[maxc];    memset (vis, false, sizeof(vis));    for (int i=R[0]; i; i=R[i])    {        if(vis[i])continue;        ret++;        vis[i]=true;        for (int j=D[i]; j!=i; j=D[j])            for (int k=R[j]; k!=j; k=R[k])                vis[C[k]]=true;    }    return ret;}int ans;void Dance(int k){                //根據具體問題選擇限制搜尋深度或直接求解。  A*演算法,此處只求最優解    if(k+h()>=ans) return;    if(!R[0]){        if(k<ans)ans=k;        return;    }    int c=R[0];    for (int i=R[0]; i; i=R[i])        if(S[i]<S[c])c=i;    for (int i=D[c]; i!=c; i=D[i]){        remove(i);        for (int j=R[i]; j!=i; j=R[j])            remove(j);        Dance(k+1);        for (int j=L[i]; j!=i; j=L[j])            resume(j);        resume(i);    }    return ;}void initL(int x){///col is 1~x,row start from 1    for (int i=0; i<=x; ++i){        S[i]=0;        D[i]=U[i]=i;        L[i+1]=i; R[i]=i+1;    }///對列表頭初始化    R[x]=0;    size=x+1;///真正的元素從m+1開始    memset (H, -1, sizeof(H));    ///mark每個位置的名字}    DLX 重複覆蓋 template

 

精確覆蓋模板

struct DLX{  int n , sz;                                                 // 行數,節點總數  int S[maxn];                                                // 各列節點總數  int row[maxnode],col[maxnode];                              // 各節點行列編號  int L[maxnode],R[maxnode],U[maxnode],D[maxnode];            // 十字鏈表  int ansd,ans[maxn];                                         // 解  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(R[0] == 0 ){      ansd = d;      return true;    }    // 找S最小的列c    int c = R[0] ;    FOR(i,R,0) if(S[i] < S[c]) c = i;    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;int main(){  int n,m;  while(scanf("%d%d",&n,&m)!=EOF)  {    solver.init(m);    int c , x;    vector<int> c1;    for(int i = 1; i<= n ; i ++ )    {      scanf("%d",&c);      c1.clear();      for(int j = 0 ; j < c ; j ++ ){scanf("%d",&x);c1.push_back(x);}      solver.addRow(i,c1);    }    vector<int> ans;    bool flag ;    flag = solver.solve(ans);    if(flag )    {      int size1 = ans.size();      printf("%d",size1);      for(int i = 0 ; i < size1;i ++ )        printf(" %d",ans[i]);      printf("\n");    }    else printf("NO\n");  }  return 0;}

  

 

SPOJ 1771&&DLX精確覆蓋,重複覆蓋

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.