[BZOJ2162]男生女生(二分图带权独立集+dp)

原创 2016年05月30日 22:01:52

题意:懒得写了,比较麻烦。

强行嵌套的题真没意思。。

开始我看见数据范围n=50,第一问求什么完全子图,我以为是个搜索减枝,然后第二问那个dp我想了想,列了几个方程发现不是很对,然后又没有部分分,我就弃疗了。。

其实想一想应该是想得出来的,主要是考试的时候写了第二题的很麻烦的做法,被折腾得没精力了,就没怎么想。。第一问其实很简单,二分图完全子图是P类的。我们求出这个二分图的补图,补图中的边就表示这两个点不能被同时选,于是就是最大点独立集了。由于要选出尽量多的男生,我们用最小割来做带权独立集即可,在S割中的男生和在T割中的女生都要选。

然后就是个DP。设f[a,b]表示a个男生b个女生中连k条边的方案(注意k是常数),可以看做在a*b的矩阵里放k个点,使得每行每列都有点。f[a,b]=C(a*b,k)-Σf[i,j]*C(a,i)*C(b,j)。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int inf = 0x3f3f3f3f;
const int mo = 19921228;
const int MAXN = 105;
void up(int&a, int b) { a+=b;if(a>=mo)a-=mo; }

int c[2505][2505], f[55][55];
void makecomb()
{
	c[0][0] = 1;
	rep(i, 1, 2500)
	{
		c[i][0]=c[i][i]=1;
		rep(j, 1, i) c[i][j] = (c[i-1][j-1]+c[i-1][j])%mo;
	}
}
int C(int n, int r)
{
	if (r>n||r<0) return 0;
	return c[n][r];
}

bool inS[105], inT[105];
struct Ed{ int to, nxt, c; };
struct FlowNet
{
	Ed e[100000];
	bool vis[MAXN];
	int ec, adj[MAXN], d[MAXN], vd[MAXN];
	int S, T, flow, vn;
	void init(int n, int s, int t)
	{
		rep(i, 1, n) adj[i] = -1;
		vn = n, S = s, T = t;
	}
	void adde(int a, int b, int c)
	{
		e[ec].to = b;
		e[ec].c = c;
		e[ec].nxt = adj[a];
		adj[a] = ec++;
		e[ec].to = a;
		e[ec].c = 0;
		e[ec].nxt = adj[b];
		adj[b] = ec++;
	}
	int aug(int u, int augco)
	{
		if (u==T) return augco;
		int delta, augc = augco, mind = vn-1;
		for (int i = adj[u], v; ~i; i=e[i].nxt)
		{
			v = e[i].to;
			if (e[i].c<=0) continue;
			if (d[u] == d[v]+1)
			{
				delta = aug(v, min(augc, e[i].c));
				e[i].c -= delta, e[i^1].c += delta;
				augc -= delta;
				if (d[S]>=vn) return augco-augc;
				if (!augc) break;
			}
			mind = min(mind, d[v]);
		}
		if (augc==augco)
		{
			if (!--vd[d[u]]) d[S] = vn;
			++vd[d[u] = mind+1];
		}
		return augco - augc;
	}
	int sap()
	{
		vd[0] = vn;
		flow = 0;
		while (d[S]<vn) flow+=aug(S, inf);
		return flow;
	}
	void dfsS(int u)
	{
		vis[u] = inS[u] = 1;
		for (int i=adj[u]; ~i; i=e[i].nxt)
			if (e[i].c>0&&!vis[e[i].to]) dfsS(e[i].to);
	}
	void dfsT(int u)
	{
		vis[u] = inT[u] = 1;
		for (int i=adj[u]; ~i; i=e[i].nxt)
			if (e[i^1].c>0&&!vis[e[i].to]) dfsT(e[i].to);
	}
	void getcut()
	{
		memset(vis,0,sizeof vis); dfsS(S);
		memset(vis, 0, sizeof vis); dfsT(T);
	}
} G;

int N, K, M, n, m;
bool love[55][55];
void solve()
{
	makecomb();
	printf("%d %d\n", n, m);
	rep(a, 1, n) rep(b, 1, m)
	{
		f[a][b] = C(a*b, K);
		rep(i, 1, a) rep(j, 1, b) if(i!=a||j!=b)
		{
			f[a][b] += mo-1ll*f[i][j]*C(a,i)%mo*C(b,j)%mo;
			f[a][b] %= mo;
		}
	}
	printf("%d\n", f[n][m]);
}

int main()
{
	freopen("boygirl.in","r",stdin);
	freopen("boygirl.out","w",stdout);
	int a, b;
	scanf("%d%d%d", &N, &K, &M);
	G.init(2*N+2, 2*N+1, 2*N+2);
	rep(i, 1, M) scanf("%d%d",&a,&b), love[a][b]=1;
	rep(i, 1, N) G.adde(G.S, i, 999), G.adde(N+i, G.T, 998);
	rep(i, 1, N) rep(j, 1, N) if (!love[i][j]) G.adde(i, N+j, inf);
	G.sap();
	G.getcut();
	rep(i, 1, N) if (inS[i]) ++n;
	rep(i, 1, N) if (inT[N+i]) ++m;
	solve();
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

二分图带权最大独立集

问题:在一个二分图中,每个点都有一个权值,在保证选中的点不相交的情况下,求选出的点的最大权值和 解法:【最小割】 前提是能把图分成二分图,比如矩阵的格子点,同一侧的各个点不会有边相连。 源点向X...
  • u012550356
  • u012550356
  • 2015年09月01日 12:04
  • 563

二分图带权最大独立集 网络流解决 hdu 1569

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total...
  • hnust_xiehonghao
  • hnust_xiehonghao
  • 2013年08月26日 13:48
  • 2469

树的最大独立集——树形dp

树的最大独立集:对于一颗n个节点的无根树,给出n-1条遍,选出尽量多的节点,使得任何两个节点均不相邻。输出一个最大独立集 分析:     d[i]:表示以i为节点的子树的最大独立集大小。 ...
  • qq_33850438
  • qq_33850438
  • 2016年02月22日 02:22
  • 1638

【NOIP2017模拟赛】二分图+状态压缩DP Graph(好题)

这道题其实是一个NPNP完全问题(2333323333),但是由于数据小啊,我们可以搞一搞。很容易发现,如果我们将一个点拆成两个点,一个代表出点,一个代表入点。当增加了一条有向边,就出点向入点连一条边...
  • C20190101ZJX
  • C20190101ZJX
  • 2017年11月09日 17:12
  • 102

二分图的最大点权独立集和最小点权覆盖集

一个定理:二分图的最小点权覆盖集对应最大点权独立集          最小点权覆盖集的建图方法:                 1、增加源点 s,连接 s 到 x 集合中所有点,边权是相应点...
  • zhjchengfeng5
  • zhjchengfeng5
  • 2012年09月08日 18:13
  • 794

二分图 最小覆盖数 = 最大匹配数、最大独立集 = 总数-最小覆盖集 证明 hdu 1068

二分图有两个定理:最小覆盖数=最大匹配数、最大独立集=总数-最小覆盖集 。 这里来给出证明(如果还不懂匈牙利算法,请先看之前写的一篇)匈牙利算法链接 几个基本定义: 最小覆盖:即在所有顶点中选择最少的...
  • Techmonster
  • Techmonster
  • 2015年11月24日 13:19
  • 2178

二分图带权匹配问题

出处:http://www.byvoid.com/blog/match-km/#respond [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,...
  • wsniyufang
  • wsniyufang
  • 2011年09月08日 11:39
  • 5882

带权二分图的最佳匹配(KM算法)

还是没看懂一般图都是最大匹配问题。。怪我太笨了哎~ 先来个看明白了的KM算法——寻找带权二分图的最佳匹配方法 一般对KM算法的描述,基本上可以概括成以下几个步骤: (1) 初始化可行标杆 (...
  • x_y_q_
  • x_y_q_
  • 2016年07月16日 23:17
  • 3645

【算法小总结】二分图的最大独立集

如果一个图是二分图,那么它的最大独立集就是多项式时间可以解决的问题了 |最大独立集| = |V|-|最大匹配数| 证明: 设最大独立集数为U,最大匹配数为M,M覆盖的顶点集合为EM。 为了证明|...
  • u013517797
  • u013517797
  • 2014年08月14日 21:19
  • 1251

HDU 1569 - 方格取数(2) 二分图最大点权独立集(构图最大流解)

题意:                       给你一个m*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并...
  • kk303
  • kk303
  • 2013年08月24日 18:31
  • 1650
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[BZOJ2162]男生女生(二分图带权独立集+dp)
举报原因:
原因补充:

(最多只允许输入30个字)