题意:
给你n个人m条关系
每条关系包含a,b
代表a和b可以是线上朋友也可以是线下朋友
然后保证每个人的线上朋友数和线下朋友数相等
问你有多少种组成方法
思路:
官方题解是爆搜+剪枝,然而并不会写。。
比赛的时候想到用高斯消元来剪枝
最后枚举自由元
因为关系的话到了最后肯定有些关系是确定的。
这样一定会消掉一些部分
最后G++AC C++TLE。。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
int equ,var;
int x[55],du[55];
int a[55][55];
int nofree_num;
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
int lcm(int x,int y)
{
return x/gcd(x,y)*y;
}
void debug()
{
for(int i=0; i<equ; i++)
{
for(int j=0; j<=var; j++) printf("%d ",a[i][j]);
puts("");
}
puts("");
}
int dfs(int p)
{
int ans=0;
if(p<nofree_num)
{
int i,j;
for(i=nofree_num-1; i>=0; i--)
{
int tep=a[i][var];
for(j=i+1; j<var; j++) tep=tep-(x[j]*a[i][j]);
if(tep%a[i][i]!=0) return 0;
x[i]=tep/a[i][i];
}
for(i=0; i<equ; i++) if(x[i]!=1 && x[i]!=-1) return 0;
return 1;
}
x[p]=-1;
ans+=dfs(p-1);
x[p]=1;
ans+=dfs(p-1);
return ans;
}
int gauss()
{
int i,j,k;
int row,col;
for(row=0,col=0; row<equ&&col<var; row++,col++)
{
int maxr=row;
for(i=row+1; i<equ; i++) if(abs(a[i][col])>abs(a[maxr][col])) maxr=i;
if(a[maxr][col]==0)
{
row--;
continue;
}
for(i=0; i<=var; i++) swap(a[row][i],a[maxr][i]);
for(i=row+1; i<equ; i++)
{
if(a[i][col])
{
int LCM=lcm(abs(a[row][col]),abs(a[i][col]));
int ta=LCM/abs(a[row][col]);
int tb=LCM/abs(a[i][col]);
if(a[i][col]*a[row][col]<0) ta=-ta;
for(j=col; j<=var; j++)
a[i][j]=(a[i][j]*tb)-(a[row][j]*ta);
}
}
}
for(i=row; i<equ; i++) if(a[i][var]) return 0;
for(i=0; i<equ; i++)
{
if(a[i][i]==0)
{
for(j=i+1; j<var; j++) if(a[i][j]) break;
if(j==var) break;
for(k=0; k<equ; k++) swap(a[k][i],a[k][j]);
}
}
nofree_num=row;
//debug();
if(var-nofree_num)
{
return dfs(var-1);
}
for(i=row-1; i>=0; i--)
{
int tep=a[i][var];
for(j=i+1; j<var; j++) tep=tep-(x[j]*a[i][j]);
if(tep%a[i][i]!=0) return 0;
x[i]=(tep/a[i][i]);
if(x[i]!=1 && x[i]!=-1) return 0;
}
return 1;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
equ=m;
var=m;
memset(a,0,sizeof(a));
memset(du,0,sizeof(du));
for(int i=0; i<m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
du[x]++;
du[y]++;
a[x-1][i]=1;
a[y-1][i]=1;
}
int ff=1;
for(int i=1;i<=n;i++)
{
if(du[i]%2)
{
ff=0;
break;
}
}
if(ff==0)
{
puts("0");
continue;
}
// debug();
int ans=gauss();
printf("%d\n",ans);
}
return 0;
}