题目
acm.hdu.edu.cn/showproblem.php?pid=4735
分析
Dancing Links 解决重复覆盖问题
先用Floyd求两点间最短距离,将<=D的连边(注意自己要跟自己连边)。
用DLX暴力搜索出所有可行的状态,更新最小值。
中间用A*进行乐观估计,如果当前用的男孩数量+估计还需要的男孩数量 > 男孩总数则return
800+msAC
代码
#include<cstring> #include<string> #include<iostream> #include<cstdio> #include<cmath> #include<vector> #include<cmath> #include<algorithm> using namespace std; #define ll long long #define pf printf #define sf scanf #define Fill(a,b) memset(a,b,sizeof(a)) const int N = 3000; const int inf = 1e9; int L[N],R[N],D[N],U[N],S[N],nCol[N]; int a[N]; int b[55][55]; int judge[N]; int n,best,num,head,dd; int boys,girls; bool vis[55]; inline void Floyd() { for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (b[i][j] > b[i][k] + b[k][j]) b[i][j] = b[i][k] + b[k][j]; } inline void init() { for (int i=0;i<=n;i++) { L[i]=i-1; R[i]=i+1; U[i]=D[i]=i; } L[0]=n; R[n]=0; int cnt=n+1; for (int i=1;i<=n;i++) { int head=cnt,tail=cnt; for (int j=1;j<=n;j++) if (b[i][j] == 1) { int c = j; S[c]++; nCol[cnt]=c; U[D[c]]=cnt; D[cnt]=D[c]; U[cnt]=c; D[c]=cnt; L[cnt]=tail; R[tail]=cnt; R[cnt]=head; L[head]=cnt; tail=cnt; judge[cnt] = i; cnt++; } } } inline void Remove(int x) { for (int i=D[x];i!=x;i=D[i]) { L[R[i]]=L[i]; R[L[i]]=R[i]; S[nCol[i]]--; } } inline void Resume(int x) { for (int i=U[x];i!=x;i=U[i]) { L[R[i]]=R[L[i]]=i; S[nCol[i]]++; } } inline int A_star() { Fill(vis,0); int ret = 0; for(int i = R[0]; i != 0; i = R[i]) if(!vis[i]) { ++ret; for(int j = D[i]; j != i; j = D[j]) { for(int k = R[j]; k != j; k = R[k]) vis[nCol[k]] = true; } } return ret; } void dfs(int ans,int sum) { //cout<<R[0]<<endl; // cout<<ans<<" "<<best<<endl; //if (tf > boys) return; if (sum + A_star() > boys) return; if (ans >= best) return; if (R[0]==0) { best=ans; return; } if (sum == boys) return; int c,minnum=inf; for (int i=R[0];i!=0;i=R[i]) { if (S[i]==0) return; if (S[i]<minnum) { minnum=S[i]; c=i; } } for (int i=U[c];i!=c;i=U[i]) { Remove(i); for (int j=R[i];j!=i;j=R[j]) Remove(j); //cout<<i<<" "<<judge[i]<<endl; //tf++; dfs(ans+(a[judge[i]] == 0),sum + 1); //tf--; for (int j=L[i];j!=i;j=L[j]) Resume(j); Resume(i); } } int main() { //freopen("in.txt","r",stdin); int T; sf("%d",&T); for (int TT = 1; TT <= T; TT++) { sf("%d%d",&n,&dd); boys = 0,girls = 0; for (int i = 1; i <= n; i++) { sf("%d",&a[i]); boys += (a[i] == 1); girls += (a[i] == 0); } Fill(b,63); for (int i = 1; i < n; i++) { int x,y,z; sf("%d%d%d",&x,&y,&z); b[x][y] = b[y][x] = z; } for (int i = 1; i <= n; i++) b[i][i] = 0; Floyd(); for (int i = 1; i<= n; i++) for (int j = 1; j <= n; j++) if (b[i][j] <= dd) b[i][j] = 1; else b[i][j] = 0; //cout<<n<<endl; continue; //for (int i = 1; i <= n; i++) //for (int j = 1; j <= n; j++) cout<<i<<" "<<j<<" "<<b[i][j]<<endl; init(); best = 1e9; dfs(0,0); if (best == 1e9) best = -1; pf("Case #%d: %d\n",TT,best); } return 0; }