第一行输入一个正偶数
代表数字个数。
第二行输入
个正整数
代表给定的数字。
输出一个整数,代表最多可以挑选出的“素数伴侣”的数量。
4 2 5 6 13
2
在这个样例中,
和
可以组成一对素数伴侣,
和
也可以组成一对素数伴侣。因此,最多可以挑选出
对素数伴侣。
4 1 2 2 2
1
在这个样例中,
只能使用一次,与任意一个
组合均是“素数伴侣”。
2 3 6
0
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
const MAX = 60000 + 1 // a+b 最大 60000
var isPrime [MAX]bool
// 线性筛法预处理素数
func sieve() {
// 从2开始,先初始化为都是素数
for i:=2;i<MAX;i++{
isPrime[i] = true
}
for i:=2;i<MAX;i++{
if isPrime[i] {
for j:= i*i;j<MAX;j+=i{ // 素数的倍数不是素数
isPrime[j] = false
}
}
}
}
/*
素数是奇数+偶数
二分图配对问题
以个数少的一方为配对基准(左图left)
优先对left中可匹配right图数较少的元素进行配对
步骤:
1)素数集求解
2)读取数据
3)奇偶分离(二分)
4)可配对情况 邻接表adj
5)尝试配对 函数dfs —— 匈牙利算法
6)开始配对,并输出结果
*/
func main() {
/* 1)素数集求解 */
sieve()
/* 2)读取数据 */
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
// 读 n
scanner.Scan()
var n int
fmt.Sscan(scanner.Text(), &n)
// 读 n 个数
nums := make([]int, n)
for i := 0; i < n; i++ {
scanner.Scan()
fmt.Sscan(scanner.Text(), &nums[i])
}
/* 3)奇偶分离(二分) */
// 分离奇偶
var odds, evens []int
for i:=0;i<n;i++{
if nums[i]%2 ==0{
evens =append(evens, nums[i])
}else{
odds = append(odds, nums[i])
}
}
// 决定哪边做左部(如果个数相差较大):选个数少的
evensLessOdd := float64((len(odds) - len(evens)))/float64(len(evens)) > 0.2
var left, right []int
var adj [][]int
if evensLessOdd {
left, right = evens, odds
} else {
left, right = odds, evens
}
/* 4)可配对情况 邻接表adj */
// 构建邻接表:left[i] 能和哪些 right[j] 配对
adj = make([][]int, len(left)) // 记录left和right中元素的索引,而非数值
var t int
for i:= 0;i<len(left);i++{
for j:=0;j<len(right);j++{
t = left[i]+right[j]
if t < MAX && isPrime[t] {
adj[i] = append(adj[i], j)
}
}
}
// (可选,由于一般相差不大,排序未必更高效)在构建 adj 后,按可匹配数升序排序 left
indices := make([]int, len(left))
for i := range indices {
indices[i] = i
}
sort.Slice(indices, func(i, j int) bool {
return len(adj[indices[i]]) < len(adj[indices[j]])
})
// 重新排序 adj(和 left,如果需要)
newAdj := make([][]int, len(left))
for i, idx := range indices {
newAdj[i] = adj[idx]
}
adj = newAdj
/* 5)尝试配对 函数dfs */
// 匈牙利算法求最大匹配
matchRight := make([]int, len(right)) // matchRight[j] = 哪个 left 的索引匹配了 right[j]
for i:=0;i<len(matchRight);i++{
matchRight[i] = -1 // -1 表示未匹配
}
var dfs func(u int, visited []bool) bool
dfs = func(u int, visited []bool) bool {
for _, i := range adj[u] {
if visited[i]{
continue
}
visited[i] = true
if matchRight[i] == -1 || dfs(matchRight[i], visited) {
matchRight[i] = u
return true
}
}
return false
}
/* 6)开始配对,并输出结果 */
var matching int =0
for i:=0;i<len(left);i++ {
visited := make([]bool, len(right))
if dfs(i, visited){
matching++
}
}
fmt.Println(matching)
} package main
import (
"fmt"
)
func isPrime(n int) bool {
if n < 2 {
return false
}
for i := 2; i*i <= n; i++ {
if n%i == 0 {
return false
}
}
return true
}
func getMax(nums []int) int {
res := 0
// 按奇偶划分
odds := []int{}
evens := []int{}
for i := 0; i < len(nums); i++ {
if nums[i]&1 == 1 {
odds = append(odds, nums[i])
} else {
evens = append(evens, nums[i])
}
}
n := len(evens)
// 为每个奇数寻找匹配的偶数
// 采用的策略:先到先得, 能让则让
// 先到先得:如果该偶数的匹配为0,就直接与之匹配
// 能让则让:如果该偶数已经匹配(匹配不为零),那么为与之匹配的奇数重新寻找匹配,如果能找到新的匹配,那么就把该偶数让给当前奇数
// 否则该奇数不能找到匹配
visited := make([]bool, n) //记录第i个偶数在本轮匹配中是否被访问过
matched := make([]int, n) //记录与第i个偶数匹配的奇数
var match func(int) bool //检查该奇数是否能找到合适的匹配, 注意:这是一个闭包函数
match = func(odd int) bool {
for i := 0; i < n; i++ {
if isPrime(odd+evens[i]) && !visited[i] {
visited[i] = true
if matched[i] == 0 || match(matched[i]) {
matched[i] = odd
return true
}
}
}
return false
}
// 为每个奇数寻找匹配
// 每轮的 visited 要清空
for _, odd := range odds {
visited = make([]bool, n)
if match(odd) {
res++
}
}
return res
}
func main() {
var n int
fmt.Scanf("%d", &n)
nums := make([]int, n)
for i := 0; i < n; i++ {
fmt.Scanf("%d", &nums[i])
}
fmt.Println(getMax(nums))
}
GO语言实现 匈牙利算法
package main
import "fmt"
import "io"
import "math"
func main(){
for {
var n int
var num int
var odds []int
var evens []int
c, err := fmt.Scanf("%d\n", &n)
if c==0 || err==io.EOF{
break
}
for i:=0; i<n; i++{
fmt.Scanf("%d", &num)
if num % 2 == 0{
evens = append(evens, num)
}else{
odds = append(odds, num)
}
}
var suited map[int]int = make(map[int]int)
var K int
for i:=0; i<len(odds); i++{
var visited map[int]int = make(map[int]int)
ok := match(odds[i], evens, visited, suited)
if ok {
K++
}
}
fmt.Println(K)
}
}
func match(odd int, evens []int, visited map[int]int, suited map[int]int) bool {
for _, even := range evens{
if isPrime(odd + even) && visited[even] == 0 {
visited[even] = 1
if suited[even] == 0 || match(suited[even], evens, visited, suited) {
suited[even] = odd
return true
}
}
}
return false
}
func isPrime(num int) bool {
n := math.Sqrt(float64(num))
n2 := int(n + 0.5)
for i := 2; i <= n2; i++{
if num%i == 0{
return false
}
}
return true
}
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <math.h> #include <algorithm> #include <vector> using namespace std; vector<int> G[105]; bool flag[105]; int pre[105]; bool dfs(int k){ int x; for(int i=0;i<G[k].size();i++){ x=G[k][i]; if (flag[x]) continue; flag[x]=true; if((pre[x]==0)||dfs(pre[x])){ pre[x]=k; return true; } } return false; } bool isprime[80000]; int nums[105]; int main(){ memset(isprime,1,sizeof(isprime)); isprime[0]=isprime[1]=false; for(int i=4;i<80000;i+=2)isprime[i]=false; for(int i=3;i*i<80000;i+=2) if(isprime[i]){ for(int j=i*i;j<80000;j+=2*i) isprime[j]=false; } int n; while(~scanf("%d",&n)){ for(int i=1;i<=n;i++){ scanf("%d",&nums[i]); } for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(isprime[nums[i]+nums[j]]){ (nums[i]&1)?G[i].push_back(j):G[j].push_back(i); } } } memset(pre,0,sizeof(pre)); int ans=0; for(int i=1;i<=n;i++){ memset(flag,false,sizeof(flag)); if (dfs(i)) ans++; } printf("%d\n",ans); for(int i=1;i<=n;++i){ G[i].clear(); } } return 0; }#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N=510; int n,m,x,y;vector<int>g[N]; namespace Blossom{ int mate[N],n,ret,nxt[N],f[N],mark[N],vis[N];queue<int>Q; int F(int x){return x==f[x]?x:f[x]=F(f[x]);} void merge(int a, int b){f[F(a)]=F(b);} int lca(int x, int y){ static int t=0;t++; for(;;swap(x,y)) if(~x){ if(vis[x=F(x)]==t) return x;vis[x]=t; x=mate[x]!=-1?nxt[mate[x]]:-1; } } void group(int a, int p){ for(int b,c;a!=p;merge(a,b),merge(b,c),a=c){ b=mate[a],c=nxt[b]; if(F(c)!=p)nxt[c]=b; if(mark[b]==2)mark[b]=1,Q.push(b); if(mark[c]==2)mark[c]=1,Q.push(c); } } void aug(int s, const vector<int>G[]){ for(int i=0;i<n;++i)nxt[i]=vis[i]=-1,f[i]=i,mark[i]=0; while(!Q.empty())Q.pop();Q.push(s);mark[s]=1; while(mate[s]==-1&&!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0,y;i<(int)G[x].size();++i){ if((y=G[x][i])!=mate[x]&&F(x)!=F(y)&&mark[y]!=2){ if(mark[y]==1){ int p=lca(x,y); if(F(x)!=p)nxt[x]=y; if(F(y)!=p)nxt[y]=x; group(x,p),group(y,p); }else if(mate[y]==-1){ nxt[y]=x; for(int j=y,k,l;~j;j=l)k=nxt[j],l=mate[k],mate[j]=k,mate[k]=j; break; }else nxt[y]=x,Q.push(mate[y]),mark[mate[y]]=1,mark[y]=2; } } } } int solve(int _n, const vector<int>G[]){ n=_n;memset(mate, -1, sizeof mate); for(int i=0;i<n;++i) if(mate[i]==-1)aug(i,G); for(int i=ret=0;i<n;++i)ret+=mate[i]>i; printf("%d\n",ret); //for(int i=0;i<n;i++)printf("%d %d\n",i+1,mate[i]+1); return ret; } } bool isprime[80000]; int nums[105]; int main(){ memset(isprime,1,sizeof(isprime)); isprime[0]=isprime[1]=false; for(int i=4;i<80000;i+=2)isprime[i]=false; for(int i=3;i*i<80000;i+=2) if(isprime[i]){ for(int j=i*i;j<80000;j+=2*i) isprime[j]=false; } while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ scanf("%d",&nums[i]); } for(int i=0;i<n;++i){ for(int j=i+1;j<n;++j){ if(isprime[nums[i]+nums[j]]){ g[i].push_back(j); g[j].push_back(i); } } } Blossom::solve(n,g); for(int i=0;i<n;++i){ g[i].clear(); } } }