题目请戳这里
题目大意:在游戏Street Fighter(街头霸王)中有若干个角色,每个角色有1~2个模式,每个角色在某个模式下可以KO另外某些模式下的某些角色。现在给n个角色和他们的模式以及各自在相应模式下能KO的对手及对手的模式。求最少需要几个角色能KO所有其他角色。
题目分析:重复覆盖问题,DLX解决。因为每个角色有1~2个模式,所以抽象出2*n行和2*n列。直接建图跑DLX即可。
需要注意的问题:
1:每个角色要对自己建边,因为自己不需要KO。
2:有的角色没有model2,所以建图后要把没有列元素的列头删掉(此处wa数次!!)
3:要判重,一个角色只能选一次。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 3000; int n,num; bool vis[55]; bool flag[55]; int data[55][55]; int ans; int h[N],s[N],u[N],d[N],l[N],r[N],row[N],col[N]; int lim; int md[26]; void init(int tn) { memset(h,0,sizeof(h)); memset(s,0,sizeof(s)); memset(flag,false,sizeof(flag)); for(int i = 0;i <= tn;i ++) { u[i] = d[i] = i; l[i] = (i + tn) % (tn + 1); r[i] = (i + 1) % (tn + 1); } num = tn + 1; } void build(int i,int j) { if(h[i]) { r[num] = h[i]; l[num] = l[h[i]]; r[l[num]] = l[r[num]] = num; } else h[i] = l[num] = r[num] = num; s[j] ++; u[num] = u[j]; d[num] = j; d[u[num]] = num; u[j] = num; col[num] = j; row[num] = i; num ++; } void prepare() { scanf("%d",&n); int i,j,m,k,a,b; init(n + n); memset(md,0,sizeof(md)); memset(data,0,sizeof(data)); for(i = 0;i < n;i ++) { scanf("%d",&md[i]); data[i<<1|1][i<<1|1] = 1; for(j = 1;j <= md[i];j ++) { scanf("%d",&m); while(m --) { scanf("%d%d",&a,&b); data[(i<<1)+j][(a<<1)+b+1] = 1; } } if(md[i] == 2) { data[i<<1|1][(i<<1)+2] = 1; data[(i<<1)+2][(i<<1)+2] = 1; data[(i<<1)+2][i<<1|1] = 1; } } for(i = 2;i <= n + n;i += 2)//!!!!!!!删除没有模式2的列头!!! if(md[(i>>1)-1] == 1) r[l[i]] = r[i],l[r[i]] = l[i]; for(i = 1;i <= n + n;i ++) { for(j = 1;j <= n + n;j ++) { if(data[i][j]) { build(i,j); } } } } 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 A() { int i,j,k,ret = 0; memset(vis,false,sizeof(vis)); for(i = r[0];i;i = r[i]) { if(vis[i] == false) { ret ++; vis[i] = true; for(j = d[i];j != i;j = d[j]) for(k = r[j];k != j;k = r[k]) vis[col[k]] = true; } } return ret; } void dfs(int k) { if(k + A() >= ans) return ; if(!r[0]) { ans = min(ans,k); return ; } int i,j,c,mn = N; for(i = r[0];i;i = r[i]) { if(s[i] < mn) { mn = s[i]; c = i; } } for(i = d[c];i != c;i = d[i]) { if(flag[(row[i] + 1)>>1] == true) continue; remove(i); flag[(row[i] + 1)>>1] = true; for(j = r[i];j != i;j = r[j]) remove(j); dfs(k + 1); for(j = l[i];j != i;j = l[j]) resume(j); resume(i); flag[(row[i] + 1)>>1] = false; } } void dance(int cas) { ans = n; dfs(0); printf("Case %d: %d\n",cas,ans); } int main() { int _,cas = 0; scanf("%d",&_); while(_ --) { prepare(); dance(++cas); } return 0; } //1937MS 340K