传送门:FZU 2141 Sub-Bipartite Graph
题目大意
有N个节点有M个边,把这N个点分为两个集合,每个边的顶点都在两个集合之内(因为选出的是子图,所以一条边的两个顶点的都在一个集合也是可以的),但是边的数量要大于等于M/2
解题思路
这个题目单纯的二分图染色的话,可能会忽略一些不满足的情况。
这个题目就是求分为两个集合,并且保留尽可能多的边。
下面就是怎么保留尽可能多的边呢?
我们枚举两个集合中的元素到顶点i的数量,如果U集合中到i顶点的数量大于V集合中的,那么就把i加入到V集合内;
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
using namespace std;
const int MAXN = 105;
int color[MAXN],cnt,head[MAXN];
int m[MAXN][MAXN];
int main()
{
int T,N,M;
int u,v;
scanf("%d",&T);
while(T--)
{
cnt = 0;
vector<int> U,V;
memset(m,0,sizeof m);
scanf("%d%d",&N,&M);
for(int i=0;i<M;i++){
scanf("%d%d",&u,&v);
m[u][v] = m[v][u] = 1;
}
//printf("{%d}\n",N);
for(int i=1;i<=N;i++){
int cntu=0,cntv=0;
for(int j=0;j<U.size();j++)
if(m[U[j]][i])cntu++;
for(int j=0;j<V.size();j++)
if(m[V[j]][i])cntv++;
if(cntu>cntv)V.push_back(i);
else U.push_back(i);
//printf("[%d,%d]\n",U.size(),V.size());
}
printf("%d",U.size());
for(int i=0;i<U.size();i++)printf(" %d",U[i]);
puts("");
printf("%d",V.size());
for(int i=0;i<V.size();i++)printf(" %d",V[i]);
puts("");
}
return 0;
}