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

来源:互联网 发布:关于php的网站 编辑:程序博客网 时间:2024/05/29 19:23

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

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

开始我看见数据范围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;}


0 0