2015编程之美初赛1 hihoCoder1158 质数相关 树形DP

来源:互联网 发布:树莓派可以装windows吗 编辑:程序博客网 时间:2024/04/29 21:22
时间限制:2000ms
单点时限:1000ms
内存限制:256MB

描述

两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。

输入

第一行为一个数T,为数据组数。之后每组数据包含两行。

第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。

输出

对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。

数据范围

1 ≤ T ≤ 20

集合S内的数两两不同且范围在1到500000之间。

小数据

1 ≤ N ≤ 15

大数据

1 ≤ N ≤ 1000


思路筛法求范围内所有质数。枚举集合内任意两个数,求它俩是否质数相关。是则加一条无向边,建图。这个图是一个无向的森林,这一点可以简单证明下:

若a1和a2有边连接到b,则有a1*p1 = a2 * p2 = b。不妨设a2 > a1。

假设a1和a2间还另有一条通路.那么有两种情况,一种存在c = a1*p3 = a2*p4。c/b 得到 p3/p1 = p4/p2 两个不同质数之比不会相等,因此矛盾。

另一种情况,a1 是 a2 的因数则有a1 * k = a2 ,那么有a1*k*p2 = a1*p1 得到k*p2 = p1 ,这与p1是质数矛盾。

因此a1 和 a2间无回。

因此可以进行树dp。因为我们要删去一些点,让森林中无边,因此父节点和它下层间最多有一层被保留,因此设计状态dp(i,j)表示i这棵子树,i节点被保留或不保留时的最多节点数。

//#include <bits/stdc++.h>   //国外OJ支持 #include <iostream>#include <stdio.h>#include <cmath>#include <cstdio>#include <vector>#include <queue>#include <algorithm>#include <cstring>#include <string>#include <cstdlib>#include <map>#include <assert.h>using namespace std;#define I64_MAX 9223372036854775807 typedef long long ll;const double pi=acos (-1.0);const double eps=1e-8 ;//const ll INF=(I64_MAX)/2;//#pragma comment(linker, "/STACK:102400000,102400000")const int inf=0x3f3f3f3f ;#define maxx(a) memset(a, 0x3f, sizeof(a))#define zero(a) memset(a, 0, sizeof(a))#define FILL(a,b) memset(a, b, sizeof(a))#define REP(i,a,b) for(i=a;i<b;i++)#define rep(i,n) REP(i,0,n)#define srep(i,n) for(i = 1;i <= n;i ++)#define snuke(c,itr) for( __typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)#define MP make_pair#define fi first#define se secondtypedef pair <int, int> PII;typedef pair <ll, ll> PX;typedef pair<int,ll> PIL;#define MAX 500000const int maxn = 1002;int n,m;bool is_prime[MAX+1];int s[maxn];int g[maxn];int dp[maxn][2];struct Edge{int u,v,next;}edge[maxn<<1];void addEdge(int u,int v){edge[m<<1].u = u;edge[m<<1].v = v;edge[m<<1].next = g[u];g[u] = (m<<1);edge[(m<<1)|1].v = u;edge[(m<<1)|1].u = v;edge[(m<<1)|1].next = g[v];g[v] = (m<<1)|1;}void sieve(){int n = MAX;for(int i=0;i<=n;i++){is_prime[i] = 1;}is_prime[0] = is_prime[1] = 0;for(int i=2;i<=n;i++){if(is_prime[i]==1){for(int j=2*i;j<=n;j+=i)is_prime[j] = false;}}}void dfs(int x){if(dp[x][0] != -1)return;dp[x][0] = 0;dp[x][1] = 1;for(int e=g[x];e!=-1;e=edge[e].next){int v =edge[e].v;if(dp[v][0] != -1)continue;dfs(v);dp[x][0] += max(dp[v][0],dp[v][1]);dp[x][1] += dp[v][0];}}int main (){    // freopen("E:\\input.txt" ,"r", stdin);    //freopen ("E:\\out.txt","w",stdout);int i,j;int T,t;memset(is_prime,0,sizeof(is_prime));sieve();scanf("%d",&T);for(t=1;t<=T;t++){m = 0;scanf("%d",&n);memset(g,-1,sizeof(g));memset(dp,-1,sizeof(dp));for(i=0;i<n;i++){scanf("%d",&s[i]);}sort(s,s+n);for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(s[j] % s[i] != 0)continue;int tmp = s[j] / s[i];if(is_prime[tmp] == 1){addEdge(i,j);m++;}}}int now = n;dp[n][0] = 0;for(i=0;i<n;i++){if(dp[i][0] == -1){dfs(i);dp[n][0] += max(dp[i][0],dp[i][1]);}}printf("Case #%d: %d\n",t,max(dp[n][0],dp[n][1]));}return 0;}


0 0
原创粉丝点击