二 分 图 状压 好题

link1

f[i][j] 表示考虑第i个点的匹配 ,前面的点匹配的集合为j的方案数

#include <bits/stdc++.h>
using namespace  std;
#define  int long long
//typedef long long ll;
typedef pair<int,int> pii;
#define x first
#define y second
#define pb  push_back
#define inf 1e18
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
const int maxn=1e5+10;
const int mod=1e9+7;
int qmi(int a,int b) {
	int res=1;
	while(b) {
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
const int N=2e5+10;
int dr[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
int n,k;
int m;
int f[1<<22][22];
int g[22][22];
void solve() {
	cin>>n;
	fer(i,0,n-1) {
		fer(j,0,n-1) {
			cin>>g[i][j];
		}
	}
	f[0][0]=1;
	for(int i=0; i<n; i++) {
		for(int j=0; j<(1<<n); j++) {
			if(__builtin_popcount(j)^i)continue;
			for(int k=0; k<n; k++) {
				if((j>>k&1)||!g[i][k])continue;
				else f[j|(1<<k)][i+1]=(f[j|(1<<k)][i+1]+f[j][i])%mod;
			}
		}
	}
	cout<<f[(1<<n)-1][n];
}

signed main() {
	IOS;
	int _=1;
	//cin>>_;
	while(_--) solve();
	return 0;
}



给定n个点完全二分图 求删除最小边权集合 仍存在完美匹配

hall定理 进行状压枚举即可

#include <bits/stdc++.h>
using namespace  std;
#define  int long long
//typedef long long ll;
typedef pair<int, int> pii;
#define x first
#define y second
#define pb  push_back
#define inf 1e18
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
int qmi( int a, int b ) {
  int res = 1;
  while( b ) {
    if( b & 1 ) res = res * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return res;
}
const int N = 2e5 + 10;
int dr[4][2] = {{ -1, 0}, {1, 0}, {0, -1}, {0, 1}};
int n, k;
int  a[100][100];
int w[N];
int ans;
void solve() {
  cin >> n;
  fer( i, 0, n - 1 ) {
    fer( j, 0, n - 1 ) {
      cin >> a[i][j];
    }
  }
  ans = ( int )( 1 << 30 );
  for( int s = 1; s < ( 1 << n ); s++ ) {
    for( int j = 0; j < n; j++ )  w[j] = 0;
    for( int i = 0; i < n; i++ )if( s & ( 1 << i ) ) {
        for( int j = 0; j < n; j++ ) {
          w[j] += a[i][j];
        }
      }
    sort( w, w + n );
    int t = n - __builtin_popcount( s ) + 1;
    int sum = 0;
    for( int k = 0; k < t; k++ )sum += w[k];
    ans = min( ans, sum );
  }
  cout << ans << endl;
}

signed main() {
  //IOS;
  int _ = 1;
  //cin>>_;
  while( _-- ) solve();
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值