题干:

大黑山上有小小民和小小涛两种物种,山东人小李想要研究这两种物种的关系

奇怪的是大黑山上有相同数量的小小民和小小涛。小李数了数一共有 P 个,小李分别给P个小小民和小小涛编号 1 - P 号,已知每对小小民之间都是好朋友,每对小小涛之间也都是好朋友,但是 i 号小小民和 j 号小小涛不一定是好朋友

山东人小李想要知道在这个物种间最大的友好群体的物种数量(在这个群体中任意两个生物都是好朋友),你能帮小李解决这个难题嘛?

Input

第一行一个整数T,代表测试数据数量

每个测试数据第一行有两个整数 P N ,大黑山上小小民或者小小涛的数量 P ,和他们之间有 N 个关系 ( 1<= P <=20 ),( 0<= N <= P^2 )

接下来 N 行每行两个整数 mi ti 表示 mi 编号的小小民和 ti 编号的小小涛是好朋友

Output

对于每个测试数据,输出一个整数表示最大的友好群体中生物的数量

Sample Input

2
4 5
1 2
2 2
3 2
4 2
1 4
3 4
1 2
2 1
1 1
2 2

Sample Output

5
4

解题报告:

   直接跑补图最大独立集就行了=二分图中顶点数-最小点覆盖。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int p,n;
bool line[22][22];
int nxt[22];
int use[22];
bool find(int x) {
	for(int i = 1; i<=p; i++) {
		if(line[x][i] && use[i] == 0) {
			use[i] = 1;
			if(nxt[i] == 0 || find(nxt[i])) {
				nxt[i] = x;
				return 1;
			}
		} 
	}
	return 0 ;
}
int match() {
	int res = 0;
	for(int i = 1; i<=p; i++) {
		memset(use,0,sizeof use);
		if(find(i)) res++;
	}
	return res;
}
int main()
{
	int t;
	cin>>t;
	while(t--) {
		memset(line,1,sizeof line);
		memset(nxt,0,sizeof nxt);
		scanf("%d%d",&p,&n);
		for(int a,b,i = 1; i<=n; i++) {
			scanf("%d%d",&a,&b);
			line[a][b]=0;
		}
		printf("%d\n",2*p-match());
	} 
	return 0 ;
}

法二:(1400ms竟然能过)

状压dp,复杂度O(n*2^n)枚举

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int bit[22];
int lowbit(int x) {return x&-x;}
int main()
{
	int t,p,n;
	cin>>t;
	while(t--) {
		scanf("%d%d",&p,&n);
		memset(bit,0,sizeof bit);
		for(int a,b,i = 1; i<=n; i++) {
			scanf("%d%d",&a,&b);
			a--;b--;
			bit[a] |= 1<<b;
		}
		int up = 1<<p,ans = 0;
		for(int sta = 0; sta<up; sta++) {//枚举选择了哪些男生 
			int tmp = up-1;//记录当前男生情况下可以获得的所有女生 
			for(int i = 0; i<p; i++) {
				if(sta&(1<<i)) tmp &= bit[i];
			}
			int sum = 0;
			for(int i = tmp; i!=0; i-=lowbit(i)) {
				sum++;
			}
			for(int i = sta; i!=0; i-=lowbit(i)) sum++;			
			ans = max(ans,sum);
		}
		printf("%d\n",ans);
	}
	return 0 ;
}