POJ 1084

题意:n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么其中会有很多诸如边长为1,为2...为n的正方形,现在可以拿走一些火柴,那么就会有一些正方形被破坏掉。问,在已经拿走一些火柴的情况下,还需要拿走至少多少根就可以把所有的正方形破坏掉。

题解:可以用dancing links做,让火柴做为行,让所有的正方形作为列,且如果i火柴能让j正方形破坏掉,就让第i行第j列为1,然后做一次可重复的覆盖,取最小值便可以得到答案。另外,涉及两个优化,

   1、最优化剪枝,即最好情况下也不会比当前最优值更优的剪枝。

   2、不必一开始就将所有的火柴棍与正方形的对应关系加入到DLX中,应该在读完所有数据之后,判断哪些正方形已经被删除了(即该列无效),只加入有效的结点。

View Code
  1 #include<cstdio>

  2 #include<cstring>

  3 #include<algorithm>

  4 using namespace std;

  5 const int inf=1<<30;

  6 const int NUM=100*60;

  7 int cnt,L[NUM],R[NUM],S[NUM],D[NUM],U[NUM],C[NUM],O[NUM],H[NUM],X[NUM];

  8 /*

  9     NUM:最大结点数

 10     U,D,L,R:上下左右结点

 11     C:列的头指针位置

 12     O:储存答案

 13     X:与O配合代表第几行(X[O[i]]])

 14     通过link(r,c)加点,dfs(0)运算

 15 */

 16 void remove(int c)

 17 {

 18     for(int i=D[c];i!=c;i=D[i])

 19     {

 20         L[R[i]]=L[i];

 21         R[L[i]]=R[i];

 22     }

 23 }

 24 void resume(int c)

 25 {

 26     for(int i=D[c];i!=c;i=D[i])

 27     {

 28         L[R[i]]=i;

 29         R[L[i]]=i;

 30     }

 31 }

 32 int geth()

 33 {

 34     bool has[80];

 35     memset(has, false, sizeof(has));

 36     int res=0;

 37     for(int i=R[0]; i!=0; i=R[i])

 38         if(!has[i])

 39         {

 40             res++;

 41             for(int j=D[i]; j!=i; j=D[j])

 42                 for(int k=R[j]; k!=j; k=R[k])

 43                     has[C[k]]=true;

 44         }

 45     return res;

 46 }

 47 int ans;

 48 void dfs(int k)

 49 {

 50     if(!R[0])

 51     {

 52         ans=min(k,ans);

 53         return;

 54     }

 55     else if(k+geth()>=ans)

 56         return;

 57     int c=R[0];

 58     for(int t=R[0],ms=inf; t!=0; t=R[t])

 59         if(S[t]<ms)

 60             ms=S[t],c=t;

 61     for(int i=D[c];i!=c;i=D[i])

 62     {

 63         remove(i);

 64         for(int j=R[i]; j!=i; j=R[j])

 65         {

 66             remove(j);

 67             S[C[j]]--;

 68         }

 69         dfs(k+1);

 70         for(int j=L[i]; j!=i; j=L[j])

 71         {

 72             resume(j);

 73             S[C[j]]++;

 74         }

 75         resume(i);

 76     }

 77 }

 78 void build(int r,int c)

 79 {

 80     for(int i=0;i<=c;i++)

 81     {

 82         U[i]=D[i]=i;

 83         L[i+1]=i;

 84         R[i]=i+1;

 85         C[i]=i;

 86         S[i]=0;

 87     }

 88     R[cnt=c]=0;

 89     while(r)

 90         H[r--]=-1;

 91 }

 92 void link(int r,int c)

 93 {

 94     ++S[C[++cnt]=c];

 95     X[cnt]=r;

 96     D[cnt]=D[c];

 97     U[D[c]]=cnt;

 98     U[cnt]=c;

 99     D[c]=cnt;

100     if(H[r]<0)

101         H[r]=L[cnt]=R[cnt]=cnt;

102     else

103     {

104         R[cnt]=R[H[r]];

105         L[R[H[r]]]=cnt;

106         L[cnt]=H[r];

107         R[H[r]]=cnt;

108     }

109 }

110 bool mark[80][80];

111 void init(int n)

112 {

113     memset(mark,false,sizeof(mark));

114     int i,j,k,si,num=0,c=1;

115     for(si=1;si<=n;si++)

116     {

117         for(i=1;i<=n-si+1;i++)

118         {

119             for(j=1;j<=n-si+1;j++)

120             {

121                 for(k=0;k<si;k++)

122                 {

123                     mark[(i-1)*(2*n+1)+j+k][c]=true;

124                     mark[(i-1+si)*(2*n+1)+j+k][c]=true;

125                     mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)][c]=true;

126                     mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)+si][c]=true;

127                 }

128                 c++;

129             }

130         }

131     }

132 }

133 int main()

134 {

135     int T,n;

136     for(scanf("%d",&T);T;T--)

137     {

138         scanf("%d",&n);

139         int num,row=2*n*(n+1),col=0;

140         for(int i=1;i<=n;i++)

141             col+=i*i;

142         build(row,col);

143         init(n);

144         scanf("%d",&num);

145         bool vis[80];

146         memset(vis,false,sizeof(vis));

147         for(int i=0;i<num;i++)

148         {

149             int r;

150             scanf("%d",&r);

151             for(int j=1;j<=col;j++)

152             {

153                 if(mark[r][j])

154                 {

155                     if(!vis[j])

156                     {

157                         vis[j]=true;

158                         R[L[j]]=R[j];

159                         L[R[j]]=L[j];

160                         R[j]=L[j]=0;

161                     }

162                 }

163             }

164         }

165         for(int i=1;i<=row;i++)

166             for(int j=1;j<=col;j++)

167                 if(mark[i][j]&&!vis[j])

168                     link(i,j);

169         ans=100000;

170         dfs(0);

171         printf("%d\n",ans);

172     }

173     return 0;

174 }

你可能感兴趣的:(poj)