Prime Companion (Niu Ke)

Title description: (Maximum matching problem of bipartite graph)

If the sum of two positive integers is prime, these two positive integers are called "prime number partners", such as 2 and 5, 6 and 13, which can be used for communication encryption. Now the Society of Cryptography asks you to design a program to select several pairs from the existing N (N is an even number) positive integers to form a "prime number companion". There are various options for selection. For example, there are 4 positive integers: 2, 5, 6, 13, if you divide 5 and 6 into a group, you can only get one set of "prime number partners", and group 2 and 5, 6 and 13 will get two groups of "prime number partners", which can form the most "prime number partners" The solution is called the "best solution". Of course, the Cryptography Society hopes that you will find the "best solution".

Enter a description:

There is a positive even number N (N≤100), which represents the number of natural numbers to be selected. N specific numbers are given in the back, the range is [2,30000].

4
2 5 6 13

Output description:

The "best solution" obtained constitutes the logarithm of the "prime number partner".

2

Maximum matching problem of bipartite graph:

1. The problem leads

Through the efforts of several generations, you have finally caught up with the tide of leftover men and women. Suppose you are a glorious matchmaker in the new century. You have N leftover men and M leftover women in your hands. Everyone may have many pairs. The opposite sex has a good impression.

If a pair of men and women have a good opinion of each other, then you can put the pair together. What you have is probably the following relationship diagram, and each connection indicates a good opinion of each other. And the current requirement is to match as many newcomers as possible.

2. Try to resolve

find(x); //表示当前对x号男生进行寻偶

line[i][j]; //表示 i 号男生和 j 号女生是否有好感
girl[j]; //表示 j 号女生的配偶编号
used[j]; //在当前挑选过程中,j号女生被used[j]号男生宣布了主权
line_num++; //x号男生牵手成功

伪代码:

used[] 为全局变量,因为发生递归时候要共用
girl[] 为全局变量,因为发生递归时候要共用
line[][] 为全局变量,因为发生递归时候要共用

for(int i=0; i<M; i++) //遍历所有男生
{
    memset(used,0,sieof(used));  //处理i号男生时候0个女生被宣布主权
    find(i);
}

bool find(int x)
{
    for(int j=0; j<N; j++)
    {    
        if( line[x][j]==1&&used[j]==0 ) //互有好感且女生没有被宣布主权
        {    
            used[j] = x; // x号男生对 j 号女生宣布主权

            if( gir[j]==0 ) //如果名花无主                 注意!!!名花无主和名花有主是可以合并在一起的,这里分开写只是为了注释方便
            {    
                girl[j] = x; // x号男生的配偶是 j 号女生
                return true; //找到了就结束
            }else{  // 名花有主的情况下,看能不能让这个主腾一下位置
                if( find(girl[j]) ){
                    girl[j] = x; // x号男生的配偶是 j 号女生
                    return true; //找到了就结束
                }
            }
        }
    }
    return false; //表示x不能再找到新的女生
}

The detailed execution process of the first two steps is given below: 

Traverse each boy in order, assuming the current boy is No. 1

① Traverse all the girls in sequence and try to find a girlfriend for boy No. 1 ( find(1) ), (at this time boy No. 1 has not declared sovereignty over any girl ( used[]={0} ))

a) It was discovered that girl No. 1 was not declared sovereign

b) I found that I have a good impression with the girl #1 line(1,1)==true

c) Declare your sovereignty over girl #1 used[1]=true

d) It is found that girl No. 1 has no owner ( girl[1]==-1 ) get, change the number of spouse of girl No. 1 ( girl[1]=1 ), and add 1 to the logarithm (blue line) line_num++ ; find(1) Return true ;

e) return false

Note: Girls have not been declared sovereignty by other people, and only if they have a good impression of each other &&Girls can get, line_num++

② Traverse all the girls in order and try to find a girlfriend for the boy No. 2 (  find(2)   ), (at this time, each boy did not declare sovereignty to any girl ( used[]={0} ))

a) It was discovered that girl No. 1 was not declared sovereign

b) It is found that the boy No. 2 and the girl No. 1 have a good impression of each other line(2,1)==true

c) Declare the sovereignty of No. 2 boy over No. 1 girl used[1]=true

d) But girl No. 1 has a master and cannot get (can't make girl[1]=2 ), at this time girl[1]=1, call find(1) to see if you can find a new girl for boy No. 1

   If find(1) is true, then get, let girl[1]=2, find(2) returns true

e) return false

At this time, let the original boyfriend of girl No. 1, that is, boyfriend No. 1 to find a new girlfriend (  find(1) ). At this time, there is already a declared sovereignty in used ( used[1]==2 ) (note At this time, the find of boy No. 1 is nested inside the find of boy No. 2 (recursion occurred), and boy No. 2 and boy No. 1 share a used[]. This used is currently only boy No. 2 has a declared sovereignty Object, this guarantees that Boy No. 1 will not choose Girl No. 1 who has been declared sovereign by Boy No. 2)

Let’s observe find(1) ,

a) No. 1 male and No. 1 girl have been declared sovereign used[1]==true , then the No. 1 guy should skip the No. 1 girl and try the No. 2 girl

b) It is found that there is a good opinion with the girl No. 2 line(1,2)==true

c) Declare the sovereignty of No. 1 boy over No. 2 girl used[2]=true

d) No. 2 girl has no owner ( girl[2]==-1 ) get, change the spouse number of girl No. 1 ( girl[2]=1 ), add 1 to the logarithm (blue line) line_num++ ; find(1) returns true;

e) return false

Question ideas:

1. First, make it clear that only an even number and an odd number are added together to produce a prime number. Therefore, we can treat all the even numbers entered as boys, and all the odd numbers entered as girls

2. The judgment of whether there is a good impression is to use one isPrime function. These multiple methods are easy to handle

3. Establish a two-dimensional matrix of favorability, and then you are done (don’t build a favorability matrix, just judge whether the two numbers are favored, otherwise the memory will exceed the limit)

AC code:

#include<iostream>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;

vector<int> even(1); //存放输入的偶数
vector<int> odd(1); //存放输入的奇数 
 
int used[100];
int girl[100]; 

bool isPrime(int num);
int isFind(int x);

int main()
{
	int n,num;
	
	while( cin>>n ){
		for(int i=1; i<=n; i++){
			cin >> num;
			if( num%2==0 ){
				even.push_back(num);
			}else{
				odd.push_back(num);
			}
		}
		
		int line_num=0;
		memset(girl,0,sizeof(girl));
		
		for(int i=1; i<even.size(); i++){
			memset(used,0,sizeof(used));
			line_num+=isFind(even[i]);
		}
		
		cout<<line_num<<endl;
		
		odd.clear();
		odd.push_back(1);
		even.clear();
		even.push_back(1);
	}
	
	return 0;
} 
bool isPrime(int num)
{
	if( num==1||num==2 ){
		return true;
	}
	if( num%6!=1&&num%6!=5 ){ //不在6倍数的两边的一定不是 
		return false;
	}
	int temp=sqrt(num); 
	for(int i=5; i<=temp; i+=6){ //在6倍数的两边也不一定是 
		if( num%i==0||num%(i+2)==0 ){
			return false;
		}
	} 
	return true;
}
int isFind(int x)
{
	for(int j=1; j<odd.size(); j++){
		if( used[j]==0&&isPrime(x+odd[j]) ){
			used[j] = x;
			if( girl[j]==0||isFind(girl[j]) ){
				girl[j] = x;
				return 1;
			}
		}
	}
	return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_40923413/article/details/106090328