题意描述:
有一个n个点m条边的二分图,通过加边使得这张图变成一个边数最多的完全二分图. 最多能够新加多少条边. 注意重边是不允许的.
解题思路:
1、先对二分图染色(dfs),统计二分图中每个连通块(注意:这个二分图并不一定连通)中黑色和白色的数量(黑、白是相对的,不同连通块之间的黑、白没有联系);
2、从每个连通块中选出黑或白的数量作为整个二分图中白色的那组,根据题目描述我们只需要找到怎样分组才能使完全二分图的边数最多(显然对于总共n个顶点的
二分图,如果两组顶点各一半时能使总的边数最大),因此我们可以使用dp得出各种分组情况。
3、由于数据10000,此处采用bitset进行优化,通过bitset运算dp出所有可能的分组情况,然后取其中使总的边数最大的情况即可
#include <cstdio> #include <cstring> #include <vector> #include <bitset> #define MAXN 10010 using namespace std; struct node { int a,b; node(int a,int b):a(a),b(b) {}; }; int n,m; int an,bn;///统计每次dfs时黑点和白点的数量 vector<int> g[MAXN]; bool flag[MAXN]; vector<node> ans;///保存二分图中每个连通块的黑点和白点数量 void dfs(int rt,bool f); int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(g,0,sizeof(g)); int x,y; for(int i=1; i<=m; ++i) { scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); } memset(flag,false,sizeof(flag)); ans.clear(); for(int i=1; i<=n; ++i) { if(!flag[i]) { an=0,bn=0; flag[i]=true; dfs(i,true); ans.push_back(node(an,bn)); } } bitset<MAXN> cur; cur.set(0);///设置第0位为1 int len=ans.size(); for(int i=0; i<len; ++i)///dp得到所有可能的黑点和白点的数量 <span style="color:#ff0000;">cur=cur<<ans[i].a|cur<<ans[i].b;///状态转移方程,cur保存了所有可能的组合</span> int anst=0; for(int i=1; i<n; ++i) if(cur[i]) anst=max(anst,(n-i)*i-m); printf("%d\n",anst); } return 0; } void dfs(int rt,bool f) { if(f)an++; else bn++; int len=g[rt].size(); for(int i=0; i<len; ++i) { if(!flag[g[rt][i]]) { flag[g[rt][i]]=true; dfs(g[rt][i],!f); } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-12 09:50:45