【BestCoder Round 65E】【网络流+讨论 奇偶分类思想】n个数形成若干至少3元素素数环的可行性检验 数可以为1

原创 2015年12月08日 09:12:48

ZYB's Prime

 
 Accepts: 5
 
 Submissions: 89
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
ZYB(ZJ-267)ZYB(ZJ267)NOIP AKNOIPAK又创造出了一道题:给出NN 个数,现在要求将它们分成KK 组(K \geq 1K1),每组数的个数都\geq 33,将每组中的数排成一个环,要求相邻的两个数加起来是个质数.ZYBZYB想要问你对于这NN个数,能不能将它们分组?
输入描述
第一行一个整数TT表示数据组数。

接下来每组数据:

  第一行一个正整数NN.

  第二行NN个正整数AiAi,描述这NN个数.

1 \leq T \leq 501T50,1 \leq N \leq 2001N200,1 \leq A_i \leq 2001Ai200,对6060%的数据N \leq 20N20.
输出描述
TT行每行输出YESYESNONO.
输入样例
2
7
3 4 8 9 1 1 1
3
1 2 3
输出样例
YES
NO


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=200+10,M=20400+10,Z=1e9+7,ms63=1061109567;
int casenum,casei;
bool e[400+10];//最大边数为(100*100+200)*2
void prime()
{
	int top=400;
	for(int i=2;i<=top;i++)if(e[i]==0)
	{
		for(int j=i+i;j<=top;j+=i)e[j]=1;
	}
}
int n,id,ST,ED;
int a[N],first[N];
int w[M],c[M],cap[M],nxt[M];
void ins(int x,int y,int cap_)
{
	id++;
	w[id]=y;
	cap[id]=cap_;
	nxt[id]=first[x];
	first[x]=id;

	id++;
	w[id]=x;
	cap[id]=0;
	nxt[id]=first[y];
	first[y]=id;
}
int d[N];
bool bfs()
{
	MS(d,-1);d[ST]=0;
	queue<int>q;q.push(ST);
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int z=first[x];z;z=nxt[z])if(cap[z])
		{
			int y=w[z];
			if(d[y]==-1)
			{
				d[y]=d[x]+1;
				if(y==ED)return 1;
				q.push(y);
			}
		}
	}
	return 0;
}
int dfs(int x,int all)
{
	if(x==ED)return all;
	int use=0;
	for(int z=first[x];z;z=nxt[z])if(cap[z])
	{
		int y=w[z];
		if(d[y]==d[x]+1)
		{
			int tmp=dfs(y,min(cap[z],all-use));
			cap[z]-=tmp;
			cap[z^1]+=tmp;
			use+=tmp;
			if(use==all)break;
		}
	}
	if(use==0)d[x]=-1;
	return use;
}
int dinic()
{
	int ans=0;
	while(bfs())ans+=dfs(ST,n*2);
	return ans;
}
bool vis[N];
int b[N][N],sum;
int p[N];
int pp[N];
bool check()
{
	int one=0,odd=0,even=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]==1)p[++one]=i;
		if(a[i]&1)
		{
			++odd;
			ins(ST,i,2);
			for(int j=1;j<=n;j++)if(a[j]!=1&&!e[a[i]+a[j]])ins(i,j,1);//细节:我们不使得1向1连边。
		}
		else
		{
			++even;
			ins(i,ED,2);
		}
	}
	if(even>odd)return 0;
	if(even==odd)return dinic()==n;
	if(/*even<odd&&*/odd-even<=one)									//这是一定会缩1的情况
	{
		int dec=odd-even;
		for(int z=first[p[one]];z;z=nxt[z])if(cap[z]==1)cap[z]=2;	//把缩的点合并成一个special one
		for(int i=1;i<=dec;++i)first[p[i]]=0;						//把去除的点都delete掉
		if(dec==one&&one<3)return 0;								//如果把1全部删掉,要求1的个数必须至少为3
		else return dinic()==even+even;
	}
	else return 0;
}
int main()
{
	prime();
	scanf("%d",&casenum);
	for(casei=1;casei<=casenum;++casei)
	{
		scanf("%d",&n);
		ST=0;ED=n+1;
		MS(first,0);id=1;
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		puts(check()?"YES":"NO");
	}
	return 0;
}
/*
【trick&&吐槽】
这题好可惜啊!
比赛的时候就差一种情况没有考虑到!就是1+x=奇数,恰好它们需要在一起的情况。
这种情况的解法是,我们考虑把1

【题意】
给你n(1<=n<=200)个数,每个数的数值范围都在[1,200]。
我们想要把这些数分为若干组。
使得——
1,每组内数的个数不超过3,
2,每组的数形成一个环,环上两两相邻的数的和都是素数。

【类型】
网络流

【分析】
这道题是 CF290(Div2)E的升级版。
不同的是,这道题的数值范围包括了1.

如果不包括1,问题会怎么样?
显然,素数不可能是2,只会是奇数。
于是,相邻两个数必定是一奇一偶。
于是,每个环中数的个数也必定为偶数个。
(题目中也必须要使得奇数和偶数的个数都相同)

然后,我们把所有奇数向与之之和为素数的偶数之间连一条流量为1的边
超级源点向所有奇数连一条流量为2的边
所有奇数向超级汇点连一条流量为2的边
然后如果最大流==点数n,那么说明有解。

这样建图,每个奇数必然会匹配到2个偶数,
于是自然使得每个组中,数的个数都必然至少为4个,保证了做法天衣无缝。

===============================================================

问题回归,现在数可以为1了。
会产生什么影响呢?
如果只有1个1,是没有任何影响的。
如果超过1个1,两个1之间是可以形成一个素数的,即,会出现奇数向奇数连边的情况。
而且,其实对我们产生干扰的,也只有1向1连边这一种情况。

(情况1)如果这些1不形成环,只是链关系的话,
我们可以考虑移除1~n-1个1,设剩余数的个数为m,我们需要查看,是否剩下的数可以跑出流量为m的最大流。
至于我么移除的1,随便和剩下的哪个1相邻即可。(也就是有一种——1个1可以拆出多个1的意味。)
这个肯定不会把是YES的情况判定为NO。这种做法下,1的个数需要至少为2个。

(情况2)然而,如果1的个数如果是大于等于3,我们是可以把所有的1都移除的。因为这些1可以自成一环。

以上做法的思想是什么呢?
就是因为发现1可以与自己相连。所以采取的一种——
"如果1多了,以至于出现1和1连边的情况了,那么我们试着减少1的数量"的做法。

(情况3)然而,这个量的减少,有时候会产生错误——
因为1的减少,我们可能一个环中只剩下2个数了。
如果有这么的一个情况出现,这种环的个数,也必然只有1个。否则2个环可以拼起来。
于是,我们缩1,不能盲目缩,我们可以缩出special one。

什么叫做special one呢?
就是这个1,连向的sum=prime的偶数的边的流量,由1变成了2。
这个解决了情况3出现的影响。也不会产生任何非法干扰。于是就可以AC掉这题啦!

【时间复杂度&&优化】
这题我会不断删点,不断做网络流。
然而流量是不断减少的,于是我们每次都要重置边的流量。
所以,我们可以使得一开始从流量最少的情况入手,不断加边。这样就不会重置边,可以有加速的奇效。

然而,我们还发现,在经过我们的缩1操作处理之后。
实际上,奇数的个数还是要和偶数个数保持相同。
因为偶数个数是不变的。所以,事实上只需要对一个值跑网络流即可。

啦啦啦啦啦~

*/


版权声明:题解中哪里写错请一定要指出来QwQ 转载还请注明下出处哦,谢谢^_^

2016蓝桥杯算法训练——最大最小公倍数

最大最小公倍数 问题描述 已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。 输入格式 输入一个正整数N。 输出格式 ...
  • qq_21385857
  • qq_21385857
  • 2016年02月13日 13:18
  • 381

1~N中随机选三个数,求其最大的 最小公倍数。

N的范围是1~10E6 自己的想法是:N 的范围比较大,自己可以选出范围内最大的那个质数Z,然后再乘以范围最大的连个不同的数,就可以得出最大的 最小公倍数。错误第一个,这样的三个数直接相乘得到其最小公...
  • Aime521
  • Aime521
  • 2015年11月09日 22:01
  • 478

C++搜索与回溯算法之素数环问题

素数环问题:从1到n(n 代码如下: #include #include int n; int num[10001]; //存储数据 bool mark[10001]; //判断该...
  • C20190413
  • C20190413
  • 2017年05月22日 22:11
  • 618

【编程之美】任意给定一个32位无符号整数n,求n的二进制表示中1的个数

任意给定一个32位无符号整数n,求n的二进制表示中1的个数,比如n = 5(0101)时,返回2,n = 15(1111)时,返回4。这也是一道比较经典的题目了,相信不少人面试的时候可能遇到过这道题吧...
  • hllyyy
  • hllyyy
  • 2015年08月24日 18:10
  • 1470

多少个1组成的整数可以被2016整除?

#include void main (){ int i=4; int j=1111; while(j!=0){ j=j*10+1; j=j%2016; i=i+1; } prin...
  • Kansas_Jason
  • Kansas_Jason
  • 2016年09月04日 09:20
  • 266

问题描述 已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。 输入格式 输入一个正整数N。 输出格式 输出一个整数,表示你找到的最小公倍数。 样例输入 9 样例输出 5

最大公约数 与最小公倍数之间的关系 贪心算法
  • Faded0104
  • Faded0104
  • 2016年12月30日 22:13
  • 338

蓝桥杯练习题——最大最小公倍数

问题描述 已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。   输入格式 输入一个正整数N。   输出格式 输出一个整数,表示你找到的最小公倍数。   样...
  • chuyueh
  • chuyueh
  • 2016年03月18日 10:25
  • 1199

小于n且与n互素的整数个数(欧拉函数)的计算

即计算1~n中与n互素的整数个数 互素就是无法被n整除的数("与p互素"和"不是p的倍数"是等价的) 所以第一种显而易见的方法就是暴力枚举法,但效率太低。 第二种方法用唯一分解定律再运用容斥原理: 分...
  • qq_34446253
  • qq_34446253
  • 2016年07月06日 15:46
  • 1534

素数环(dfs递归实现)

题意:给定一个数,输出该数能够形成的素数环的所有方案。链接:http://acm.hdu.edu.cn/showproblem.php?pid=1016思路:dfs递归实现,三个数组,一个存环的每个位...
  • qq_35399846
  • qq_35399846
  • 2016年07月22日 15:07
  • 713

算法训练 最大最小公倍数(转)

算法训练 最大最小公倍数 时间限制:1.0s 内存限制:256.0MB 问题描述 已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。输入格式 输入一个正整数N。输...
  • fourteen_zhang
  • fourteen_zhang
  • 2017年03月14日 22:47
  • 95
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【BestCoder Round 65E】【网络流+讨论 奇偶分类思想】n个数形成若干至少3元素素数环的可行性检验 数可以为1
举报原因:
原因补充:

(最多只允许输入30个字)