题目:首先由T组数据
每组数据下是 n,m 。n个人(两边各)m组关系
2->接下来m行 每行 a,b,A监狱中的a ,不能与B中的b 一起
刚开始拿到这一道题的时候一点思路也没有,如何能够做。
首先发现几个事实:
1.n数据范围很小
2.如果这个人和其他的人之间有关系,那么变动一个人就需要变动多个人,才能保证不会发生冲突
所以,定义f[ i ][ j ]表示A监狱中选i个人B监狱中选j个人是否可行,可行为1。那么现在先用dfs找出所有有关联的人,进行打包,就有点像tarjan缩点那么一点意思,因为这些人互相关联,影响一个就会影响全部,so,把每一个打包后的人看作一个物品就变成了二维的01背包,三层for递推
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 405
#define Clear(x) memset(x,0,sizeof(x))
#define PB push_back
#include<vector>
using namespace std;
int f[maxn][maxn],dfn[maxn],l[maxn],r[maxn],n,m,q,p;
vector<int>g[maxn];
void dfs(int u){
dfn[u]=1;
if(u<=n)p++;
else q++;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(dfn[v])continue;
dfs(v);
}
}
int main(){
int T;
cin>>T;
while(T--){
int cnt=0;
cin>>n>>m;
Clear(f);Clear(dfn);Clear(l);Clear(r);
for(int i=1;i<=n*2;i++)g[i].clear();
for(int a,b,i=1;i<=m;i++){
scanf("%d%d",&a,&b);
g[a].PB(b+n);
g[b+n].PB(a);
}
for(int i=1;i<=2*n;i++){
if(dfn[i])continue;
p=q=0;
dfs(i);
l[++cnt]=p;r[cnt]=q;
}
f[0][0]=1;
for(int i=1;i<=cnt;i++){//两个均可
for(int j=n/2;j>=0;j--){
for(int k=n/2;k>=0;k--){
if(f[j][k]==1){
f[j+l[i]][k+r[i]]=1;
}
}
}
}
/*for(int i=1;i<=cnt;i++){//也可以,看习惯
for(int j=n/2;j>=l[i];j--){
for(int k=n/2;k>=r[i];k--){
if(f[j-l[i]][k-r[i]])f[j][k]=1;
}
}
}*/
for(int i=n/2;i>=0;i--){
if(f[i][i]){
printf("%d\n",i);
break;
}
}
}
return 0;
}