Codeforces Gym 101173B / BZOJ 4788 Bipartite Blanket 二分图Hall定理+状态压缩DP

Problem B: Bipartite Blanket

Time limit: 3 s

Memory limit: 512 MiB

In a bipartite graph, nodes are partitioned into two disjoint sets A and B such that every edge connects anode from A with a node from B. A matching M is a set of edges where no two edges share a common node. We say that a matching M blankets a set of nodes V if every node in V is an endpoint of at least one edge in M.

We are given a bipartite graph where each node is assigned a weight — a positive integer. Weight of a set of nodes is simply the sum of the weights of the individual nodes.

Given an integer threshold t, find the number of different sets of nodes V such that the weight of V is at least t and V is blanketed by at least one matching M.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 20) — the number of nodes in A and B respectively. Let us denote the nodes of A with a1, a2, . . . , an and the nodes of B with b1, b2, . . . , bm.

The following n lines contain m characters each that describe the edges of the graph. The j-th character in the i-th line is “1” if there is an edge between ai and bj and “0” otherwise.

The following line contains n integers v1, v2, . . . , vn (1 ≤ vk ≤ 10 000 000) — the weights of the nodes a1, a2, . . . an. 

The following line contains m integers w1, w2, . . . , wm (1 ≤ wk ≤ 10 000 000) — the weights of the nodes b1, b2, . . . bm. The following line contains an integer t (1 ≤ t ≤ 400 000 000) — the weight threshold.

Output

Output the number of sets of nodes whose weight is at least t and are blanketed by at least one matching M.


有一个二分图,把一个能够被某一合法匹配完全覆盖的点集当做合法的。

问这些合法的点集当中,有多少个权值和大于t.


Hall定理:

X或Y集合其中一个集合所有点都被匹配了,X集合有n个点。 
那么二分图G存在完美匹配,则取任意正整数1<=k<=n,均满足我从X集合选出k个不同的点,那么它们连向的y集合的点个数不小于k。

根据Hall定理枚举两个集合当中点的状态(取或不取),将所有可能点集的权值和求出,双指针lower_bound累加得到答案。点集用状态压缩表示,DP转移。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=25,maxk=(1<<20)+5,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
ll a[maxn],b[maxn];
ll ax[maxk],bx[maxk],aw[maxk],bw[maxk];
bool af[maxk],bf[maxk];   
ll cnt[maxk];
char s[maxn][maxn];

int main() {
	int n,m,na,nb,i,j;
	scanf("%d%d",&n,&m);
	for (i=0;i<n;i++) {
		scanf("%s",s[i]);
		for (j=0;j<m;j++) 
			if (s[i][j]=='1') aw[1<<i]|=1<<j,bw[1<<j]|=1<<i;
	}
	for (i=0;i<n;i++) 
		scanf("%lld",&a[i]);
	for (i=0;i<m;i++)
		scanf("%lld",&b[i]);
	cnt[0]=0;
	for (i=1;i<max(1<<n,1<<m);i++) 
		cnt[i]=cnt[i/2]+i%2;
	ll t;
	scanf("%lld",&t);
	na=nb=0;
	for (i=0;i<(1<<n);i++) {
		ll sum=0;
		af[i]=1;
		for (j=0;j<n;j++) {
			if ((i>>j)%2==1) {
				sum+=a[j];                    //当前状态的点的权值和
				aw[i]=aw[i]|aw[i^(1<<j)];     //对应另一组点的状态
				af[i]=af[i]&af[i^(1<<j)];     //状态合法性转移
			}
		}
		af[i]=af[i]&&(cnt[i]<=cnt[aw[i]]);
		if (af[i]) 
			ax[na++]=sum;
	}
	for (i=0;i<(1<<m);i++) {
		ll sum=0;
		bf[i]=1;
		for (j=0;j<m;j++) {
			if ((i>>j)%2==1) {
				sum+=b[j];
				bw[i]=bw[i]|bw[i^(1<<j)];
				bf[i]=bf[i]&bf[i^(1<<j)];
			}
		}
		bf[i]=bf[i]&&(cnt[i]<=cnt[bw[i]]);
		if (bf[i]) 
			bx[nb++]=sum;
	}
	sort(ax,ax+na);
	ll ans=0;
	for (i=0;i<nb;i++) {
		ans+=na-(lower_bound(ax,ax+na,t-bx[i])-ax);
	}
	printf("%lld\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。GymCodeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值