//http://sqybi.com/works/dlxcn/
/*
同时有部分覆盖与完全覆盖时,尝试取某一行时,一定要先去掉部分覆盖的列,再去完全覆盖的列。
因为去完全覆盖的列时,会把部分覆盖的列的关系打乱,使后面再去部分覆盖时找不到了,无法结束。
hdu3957每个角色最多有两个身份,给出每个角色的身份的胜败关系,选出最少的角色的某个身份,
使得无论其它角色选择什么身份,至少有一个你选的角色打败它。
*/
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxr=55;
const int maxc=110;
const int maxn=11000;
int L[maxn],R[maxn],U[maxn],D[maxn],RH[maxn],CH[maxn],ynum[maxc];
int sum,r,c,size,head;
bool mat[maxr][maxc],vis[maxc];
int AddNode(int l,int r,int u,int d)
{
L[size]=l,R[size]=r,U[size]=u,D[size]=d;
L[r]=R[l]=U[d]=D[u]=size;
return size++;
}
void Make()
{
int i,j,k;
memset(ynum,0,sizeof(ynum));
size=0;
head=AddNode(size,size,size,size);
for(i=0;i<c;i++)
{
CH[i+1]=i;
AddNode(L[head],head,size,size);
}
for(i=0;i<r;i++)
for(k=-1,j=0;j<c;j++)
{
if(!mat[i][j]) continue;
RH[size]=i,CH[size]=j,ynum[j]++;
if(k==-1)
k=AddNode(size,size,U[j+1],j+1);
else k=AddNode(k,R[k],U[j+1],j+1);
}
for(i=0;i<c;i++)
if(!ynum[i])
L[R[i+1]]=L[i+1],R[L[i+1]]=R[i+1];
}
void Remove(int c)//完全覆盖的去除c列元素的行
{
L[R[c]]=L[c],R[L[c]]=R[c];
int i,j,k;
for(i=U[c];i!=c;i=U[i])
for(j=R[i];j!=i;j=R[j])
ynum[CH[j]]--,U[D[j]]=U[j],D[U[j]]=D[j];
}
void Resume(int c)
{
int i,j,k;
for(i=D[c];i!=c;i=D[i])
for(j=L[i];j!=i;j=L[j])
ynum[CH[j]]++,U[D[j]]=D[U[j]]=j;
L[R[c]]=R[L[c]]=c;
}
void Remove1(int c)//部分覆盖去除c列
{
int i;
for(i=U[c];i!=c;i=U[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void Resume1(int c)
{
int i;
for(i=D[c];i!=c;i=D[i])
L[R[i]]=R[L[i]]=i;
}
int h()
{
int i,j,k,num=0;
memset(vis,false,sizeof(vis));
for(i=R[head];i!=head&&i<=r;i=R[i])
if(!vis[CH[i]])
{
num++;
vis[CH[i]]=true;
for(j=U[i];j!=i;j=U[j])
for(k=R[j];k!=j;k=R[k])
vis[CH[k]]=true;
}
return num;
}
void DFS(int t)
{
if(t+h()>=sum) return;//部分覆盖的IDA*
if(R[head]==head||R[head]>r)
{
if(sum>t) sum=t;
return;
}
int i,j,k;
for(k=-1,i=R[head];i!=head&&i<=r;i=R[i])
if(k==-1||ynum[CH[i]]<ynum[CH[k]])
k=i;
//printf("%d %d\n",t,k);
for(i=U[k];i!=k;i=U[i])
{
Remove1(i);//先去掉部分覆盖的
for(j=R[i];j!=i;j=R[j])
if(CH[j]<r) Remove1(j);
for(j=R[i];j!=i;j=R[j])//再去完全覆盖
{
if(CH[j]>=r) Remove(CH[j]+1);
// else Remove1(j); //混着写是错的,无法正常结束
}
DFS(t+1);
for(j=L[i];j!=i;j=L[j])
{
if(CH[j]>=r) Resume(CH[j]+1);
// else Resume1(j);
}
for(j=L[i];j!=i;j=L[j])
if(CH[j]<r) Resume1(j);
Resume1(i);
}
}
int main()
{
int t,test=1,n,i,j,k,kk,u,v;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(mat,false,sizeof(mat));
for(i=0;i<n;i++)
{
scanf("%d",&k);
for(j=0;j<k;j++)
{
if(k==2)
mat[i*2+j][i*2+(j^1)]=true;
mat[i*2+j][i*2+j]=true;
mat[i*2+j][n*2+i]=true;
scanf("%d",&kk);
while(kk--)
{
scanf("%d%d",&u,&v);
mat[i*2+j][u*2+v]=true;
}
}
}
r=n*2,c=n*3;
Make();
sum=r;
DFS(0);
printf("Case %d: %d\n",test++,sum);
}
return 0;
}
//hdu3111求9*9的数独
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxr=1100;
const int maxc=410;
const int maxn=maxr*maxc;
int o[maxn],L[maxn],R[maxn],U[maxn],D[maxn],RH[maxn],CH[maxn],ynum[maxc];
int size,head,r,c,g[10][10];
bool mat[maxr][maxc];
int AddNode(int l,int r,int u,int d)
{
L[size]=l,R[size]=r,U[size]=u,D[size]=d;
L[r]=R[l]=U[d]=D[u]=size;
return size++;
}
void Remove(int c)//删除c列
{
L[R[c]]=L[c],R[L[c]]=R[c];
int i,j;
for(i=U[c];i!=c;i=U[i])
for(j=R[i];j!=i;j=R[j])
D[U[j]]=D[j],U[D[j]]=U[j];
}
void Resume(int c)//恢复c列
{
int i,j;
for(i=D[c];i!=c;i=D[i])
for(j=L[i];j!=i;j=L[j])
D[U[j]]=U[D[j]]=j;
L[R[c]]=R[L[c]]=c;
}
bool DFS(int kk)
{
if(R[head]==head) return true;
int i,j,k;
for(k=-1,i=R[head];i!=head;i=R[i])//找含最少元素的列
if(k==-1||ynum[CH[i]]<ynum[CH[k]])
k=i;
Remove(k);
for(i=U[k];i!=k;i=U[i])//枚举这列元素所在的行
{
o[kk]=RH[i];
for(j=R[i];j!=i;j=R[j])
Remove(CH[j]+1);
if(DFS(kk+1)) return true;
for(j=L[i];j!=i;j=L[j])
Resume(CH[j]+1);
}
Resume(k);
return false;
}
void Make()
{
int i,j,k;
memset(mat,false,sizeof(mat));
for(i=0;i<9;i++)
for(j=0;j<9;j++)
for(k=1;k<=9;k++)
if(!g[i][j]||g[i][j]==k)
{
mat[i*9*9+j*9+k-1][i*9+j]=true;
mat[i*9*9+j*9+k-1][9*9+i*9+k-1]=true;
mat[i*9*9+j*9+k-1][2*9*9+j*9+k-1]=true;
mat[i*9*9+j*9+k-1][3*9*9+(i/3*3+j/3)*9+k-1]=true;
}
r=9*9*9;
c=4*9*9;
size=0,head=0;
memset(ynum,0,sizeof(ynum));
AddNode(size,size,size,size);
for(i=0;i<c;i++)
{
CH[size]=i;
AddNode(L[head],head,size,size);
}
for(i=0;i<r;i++)
for(k=-1,j=0;j<c;j++)
{
if(!mat[i][j]) continue;
RH[size]=i,CH[size]=j,ynum[j]++;
if(k==-1)
k=AddNode(size,size,U[j+1],j+1);
else k=AddNode(k,R[k],U[j+1],j+1);
}
}
int main()
{
int t,i,j;
char ch[110];
scanf("%d",&t);
getchar();
while(t--)
{
for(i=0;i<9;i++)
{
gets(ch);
for(j=0;j<9;j++)
{
if(ch[j]=='?') g[i][j]=0;
else g[i][j]=ch[j]-'0';
}
}
Make();
if(!DFS(0))
printf("impossible\n");
else
{
sort(o,o+81);
for(i=0;i<81;i++)
{
printf("%d",o[i]%9+1);
if(i%9==8) printf("\n");
}
}
if(t)
{
printf("---\n");
gets(ch);
}
}
return 0;
}