B - poset
2016-09-20 15:54
120 查看
不想打了。。
分配小组(poset.pas)
[问题描述]
有N个Mars人想要进行一项活动。他们需要分成几个小组,每个人属于其中一个小组。Mars人从出生起每个人就有一个印记,这个印记是个正整数。如果B的印记是A的倍数,那么B就是A的父亲。与地球人的定义不现,一个Mars人可以有多个父亲。特别的,A不是自己的父亲,但是所有其他与A的印记相同的人都是A的父亲。因此,除了A自己,A的父亲的父亲都是A的父亲。
Mars人十分强调子女的独立,因此进行这项活动的分组时,任何人都不能和自己的父亲分到同一个小组。你的任务就是对于给定的Mars人,给出一种分组方案,使得小组的数量最少。显然,这个问题一定存在可行解——你可以让每个Mars人单独一组。如果有多解,任意输出一组即可。
[输入文件]
第一行:一个整数N,表示Mars人的数量。
接下来一行有N个正整数,表示每个Mars人的印记。
[输出文件]
前K行,每行包含若干个整数,每一行的整数表示相应小组的每个人的印记。相邻整数用一个空格分开,每一行的末尾应该保留一个空格。
最后一行是一个整数K,表示你分成的小组数量。
[样例输入]
5
1 1 3 1 5
[样例输出]
1
1
1
3 5
4
[样例说明]
三个1必须分别分成一组;3和5不是倍数关系,可以分成一组。
[数据规模及约定]
N<=5000
1<=所有印记<=5000
2333
很显然1只有自己在一个集合。
首先我们排一次序,这样可以避免小数除大数等等诸多不便。
然后,对于一个数,我们枚举比它小的数。如果一个数不能整除这个数,并且它所在集合的其它数也不能整数这个数,那么就把它加入这个集合。
如果集合中有一个数能整除,那就没得谈了。
这样的理论依据是:如果一个数能加入某个集合,这最好。如果不能,那么这个集合中包含两部分:一部分是不能整除的数,可以同当前数组成集合;另一部分数不能。这时,如果我们把这个集合拆成两部分,让当前数加入前者,结果还是有两个集合;而不加入此集合,最坏情况下也还是有两个集合。
也就是说,只要加入,就只会赚,不会赔。说白了也就是一个贪心。
std:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[5010];
bool f[5010];
struct point
{
int x;
point *next;
}*p[5010];
bool find(int i,int j)
{
for (point *k=p[j]; k; k=k->next)
if (!(a[i] % k->x)) return 0;
return 1;
}
void insert(int i,int j)
{
point *now=new point;
now->x=a[i]; now->next=p[j]; p[j]=now;
}
int main()
{
freopen("poset.in","r",stdin);
freopen("poset.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for (int i=2; i<=n; i++)
for (int j=1; j<i; j++)
if (!f[j] && (a[i] % a[j]))
if (find(i,j))
{
f[i]=1;
insert(i,j);
break;
}
int ans=0;
for (int i=1; i<=n; i++)
if (!f[i]) ++ans;
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
然而貌似DP也可以搞
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int N,a[5005],f[5005],ans;
int main()
{
freopen("poset.in","r",stdin);
freopen("poset.out","w",stdout);
scanf("%d",&N);
for (int i=1;i<=N;i++) scanf("%d",&a[i]),f[i]=1;
sort(a+1,a+1+N);
for (int i=1;i<=N;i++)
{
for (int j=1;j<i;j++)
{
if (!(a[i] % a[j]))
{
f[i]=max(f[i],f[j]+1);
}
}
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}
分配小组(poset.pas)
[问题描述]
有N个Mars人想要进行一项活动。他们需要分成几个小组,每个人属于其中一个小组。Mars人从出生起每个人就有一个印记,这个印记是个正整数。如果B的印记是A的倍数,那么B就是A的父亲。与地球人的定义不现,一个Mars人可以有多个父亲。特别的,A不是自己的父亲,但是所有其他与A的印记相同的人都是A的父亲。因此,除了A自己,A的父亲的父亲都是A的父亲。
Mars人十分强调子女的独立,因此进行这项活动的分组时,任何人都不能和自己的父亲分到同一个小组。你的任务就是对于给定的Mars人,给出一种分组方案,使得小组的数量最少。显然,这个问题一定存在可行解——你可以让每个Mars人单独一组。如果有多解,任意输出一组即可。
[输入文件]
第一行:一个整数N,表示Mars人的数量。
接下来一行有N个正整数,表示每个Mars人的印记。
[输出文件]
前K行,每行包含若干个整数,每一行的整数表示相应小组的每个人的印记。相邻整数用一个空格分开,每一行的末尾应该保留一个空格。
最后一行是一个整数K,表示你分成的小组数量。
[样例输入]
5
1 1 3 1 5
[样例输出]
1
1
1
3 5
4
[样例说明]
三个1必须分别分成一组;3和5不是倍数关系,可以分成一组。
[数据规模及约定]
N<=5000
1<=所有印记<=5000
2333
很显然1只有自己在一个集合。
首先我们排一次序,这样可以避免小数除大数等等诸多不便。
然后,对于一个数,我们枚举比它小的数。如果一个数不能整除这个数,并且它所在集合的其它数也不能整数这个数,那么就把它加入这个集合。
如果集合中有一个数能整除,那就没得谈了。
这样的理论依据是:如果一个数能加入某个集合,这最好。如果不能,那么这个集合中包含两部分:一部分是不能整除的数,可以同当前数组成集合;另一部分数不能。这时,如果我们把这个集合拆成两部分,让当前数加入前者,结果还是有两个集合;而不加入此集合,最坏情况下也还是有两个集合。
也就是说,只要加入,就只会赚,不会赔。说白了也就是一个贪心。
std:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[5010];
bool f[5010];
struct point
{
int x;
point *next;
}*p[5010];
bool find(int i,int j)
{
for (point *k=p[j]; k; k=k->next)
if (!(a[i] % k->x)) return 0;
return 1;
}
void insert(int i,int j)
{
point *now=new point;
now->x=a[i]; now->next=p[j]; p[j]=now;
}
int main()
{
freopen("poset.in","r",stdin);
freopen("poset.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for (int i=2; i<=n; i++)
for (int j=1; j<i; j++)
if (!f[j] && (a[i] % a[j]))
if (find(i,j))
{
f[i]=1;
insert(i,j);
break;
}
int ans=0;
for (int i=1; i<=n; i++)
if (!f[i]) ++ans;
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
然而貌似DP也可以搞
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int N,a[5005],f[5005],ans;
int main()
{
freopen("poset.in","r",stdin);
freopen("poset.out","w",stdout);
scanf("%d",&N);
for (int i=1;i<=N;i++) scanf("%d",&a[i]),f[i]=1;
sort(a+1,a+1+N);
for (int i=1;i<=N;i++)
{
for (int j=1;j<i;j++)
{
if (!(a[i] % a[j]))
{
f[i]=max(f[i],f[j]+1);
}
}
ans=max(ans,f[i]);
}
printf("%d",ans);
return 0;
}
相关文章推荐
- C#模拟http 发送post或get请求的简单实例
- Transformation 能将 Windows XP/Server 2003 操作系统,完美地模拟成 Windows Vista 的软件
- 用javascript和css模拟select的脚本
- PHP模拟asp.net的StringBuilder类实现方法
- C#使用ImitateLogin模拟登录百度
- javascript用层模拟可移动的小窗口
- JS模拟简易滚动条效果代码(附demo源码)
- 自编jQuery插件实现模拟alert和confirm
- JS模拟按钮点击功能的方法
- JS模拟的Map类实现方法
- PHP模拟asp中response类实现方法
- 模拟Spring的简单实现
- javascript 模拟点击广告
- JQuery中模拟image的ajaxPrefilter与ajaxTransport处理
- php实现模拟post请求用法实例
- JavaScript实现MIPS乘法模拟的方法
- 模拟xcopy的函数
- JS模拟实现Select效果代码
- php模拟服务器实现autoindex效果的方法
- C# SendInput 模拟鼠标操作的实现方法