1. 程式人生 > 實用技巧 >zoj3988(自己集合和自己集合匹配)

zoj3988(自己集合和自己集合匹配)

題:https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370128

題意:給定n個數(n<=3e3)倆者能匹配的充分必要條件未倆者之和為質數,求至多匹配完k對後各個數所屬下標的並集最大是多少;

分析:二分圖直接匈牙利演算法搞起,主要k限制,那就判斷匹配數和k之間關係;

   若ans<=k,那麼匹配數足以貪心地輸出2*k;

   否則看剩下有多少個,1個就有一個貢獻,因為經過最大匹配後另一個一定被匹配完了;

#include<bits/stdc++.h>
using namespace std;
const int
mod=1e9+7; const int M=3e3+5; typedef long long ll; #define pb push_back const int N=2e6+6; const int inf=0x3f3f3f3f; int mp[M],vis[M],a[M]; int n; int prime[N]; vector<int>g[M]; void init(){ for(int i=2;i<N;i++){ if(!prime[i]){ for(int j=i+i;j<N;j+=i) prime[j]
=1; } } } int dfs(int u){ vis[u]=1; for(auto v:g[u]){ if(!vis[v]){ vis[v]=1; if(mp[v]==-1||dfs(mp[v])){ mp[v]=u; mp[u]=v; return 1; } } } return 0; } int xiong(){ int res=0
; for(int i=1;i<=n;i++) if(mp[i]==-1){///一般的匈牙利演算法不用這句,這題加代表選過了不能再選,只能從未選過的開始選 memset(vis,0,sizeof(vis)); res+=dfs(i); } return res; } int main(){ int T; scanf("%d",&T); init(); while(T--){ int k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),mp[i]=0,g[i].clear(); int sum=0; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++) if(!prime[a[i]+a[j]]){ ///cout<<i<<" "<<j<<endl; g[i].pb(j),g[j].pb(i); mp[i]=-1,mp[j]=-1; } } int ans=xiong(); if(ans>=k){ printf("%d\n",k*2); } else{ int leave=0; for(int i=1;i<=n;i++) if(mp[i]==-1) leave++; printf("%d\n",2*ans+min(k-ans,leave)); } } return 0; }
View Code