12/28 图论搜索测试总结

真的跪了

时间分配极欠妥当。心态不稳定,处于“暴力写不好”“正解没时间写”的绝妙境地。
会建图,反而是算法的具体实施很不熟练。细节处欠缺太多。

多自主思考。

T1 促销

【问题描述】
小x在jzyz开了一家冷饮店,因为刚开张,他决定做一次促销活动。而活动的获奖者可以免费得到一杯圣代。
为了和同学的生活贴近,小x费劲脑汁想到了一个促销方案:
1) 当场摇出一个正整数M,再摇出两个正整数X和Y
2) 每个人可以在1..M这M个自然数中挑出N个不同的数。
3) 如果某人可以在现场把这N个数的倒数的累加和恰好等于X/Y,那么这个人可以得到一杯圣代。
4) 每种方案只限第一名想到答案的领取一杯圣代。
现在小x苦恼的是,对于给定的N,M,X,Y,他能否尽快得知他最多要准备多少杯圣代。
【输入】
四个整数:N,M,X,Y。
【输出】
一个整数,表示最多要准备多少杯圣代。

【输入样例】
2 4 3 4

【输出样例】
1

【数据范围】
对于30%的数据,1<=N<=M<=15
对于60%的数据,1<=N<=M<=20
对于100%的数据,1<=N<=M<=25,X<=25,Y<=25

看到这题的第一瞬间脑内就是,“要被卡精度了”,果然被卡了。
想过用gcd,又觉得可行性低,没有写,后来同学有人写出来了,哎。
暴力搜索。
可行性剪枝:没取到n个数累加和已超过x/y。
最优化剪枝:由于取数是有顺序的,故比当前数x小的数都已经取过,即下次取数区间为[x+1,m]。

挨个取数,没必要另开数组判断取没取过了。

精度啊精度

#include<bits/stdc++.h>
using namespace std;

int x,y,m,n;
double summ=0.00;
int ans=0;
double a=0.00;

void dfs(int step,double summ,int x)
{
    if(step==n) {
        if(abs(summ-a)<=0.0000001) ans++;//误差在一定范围内可接受,即为一解。
        return;
    }
    if(summ-a>0.00000001) return;//可行性剪枝。
    for(int i=x+1;i<=m;++i)//最优化剪枝。
        dfs(step+1,summ+1.0/i,i);
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&x,&y);
    a=(1.00*x)/(1.00*y);
    dfs(0,summ,0);
    cout<<ans;
    return 0;
}

涉及double 这个妖艳贱货一定 要注意注意非常注意。


T2 特殊字典序

【问题描述】
Bessie发现了一些很奇怪的残缺的字典,这些字典的单词是按照某种特殊的字典序排序的,现在Bessie给你多组按照特殊字典序给出的单词组,问你能不能给出这些字母的先后顺序。
比如按顺序给出4个单词:ula uka klua kula al。这里只有四个小写字母,分别是:u l k a。 根据首字母我们知道 u< k< a,根据klua 和 kula 知道 l< u,于是我们知道字典序是luka.
比如给定另4个单词:jaja baba baja beba。我们发现既有j< b,也有b< j,存在矛盾的先后关系,对于此种情况,我们输出 “!”。
再比如给定3个单词:marko darko zarko ,无法确定一些的关系,对于这种情况,我们输出 “?”
【输入】
多组数据
每组数据第一行一个整数N (1≤ N ≤ 100)
接下来N行,每行一个单词,保证单词由小写字母组成,且长度不超过10.
【输出】
多行,每行按要求输出相应的结果。

看到输入方式就开始烦躁了。第一眼拓扑第二眼还是拓扑,遂义无反顾走了下去。建图建得感动自己,临到这拓扑怎么判环怎么输出顺序忘得一干二净。等想起来整个人已经烦躁到炸裂了。
没想到可以用floyed,其实该想到的,因为26*26*26,几乎是为floyed量身打造。果然floyed还是最强的。

然而还没有调出来


T3 星级隧道

【问题描述】
小x当上了银河系的国王,一共统治了N个星球,现在帝国要建立N-1条星际隧道,将所有的星球全部连接起来。
每个星球都有自己的立体坐标。xA,yA,zA表示星球A的三维坐标,xB,yB,zB分别表示星球B的三维坐标.在A和B两个星球建立通道的代价是:
Cost[A,B] = min{ |xA-xB|, |yA-yB|, |zA-zB| }

现在小x想知道,最少要花费多少代价,能将这N个星球用星级隧道连接起来。

【输入】
第一行包含1个整数N(1<=N<=100000),表示星球的数目。
接下来N行包含3个整数,所有整数介于-10^9到10^9之间.每一行包含x,y,z,表示该星球的三个坐标。
注意:没有两个在空间中的同一点。

【输出】
只有1行,表示最小的代价。

【样例输入】
5
11 -15 -15
14 -5 -15
-1 -1 -5
10 -4 -1
19 -4 19

【样例输出】
4

直白的最小生成树。显然的稠密图。最开始的想法,是每两个点之间连边搞,会MLE+TLE双享。考完才发现如果用prim是不用存边的。我大概是失去了脖子以上的部分。

因为prim是基于点的算法,故点与点之间的联系可以临时计算,完全ok。
copy一下cxgg的代码:
这里写图片描述
这里写图片描述

就是活生生的裸的prim,怪我太浅薄。

但是prim O(n^2),这里会超时。后来想到正解Kruskal,居然死于快读。可恶啊,然而。

Kruskal基于边实现,既然躲不开存边那就存吧。两点间路径为xyz坐标差的最小值,故可将星球分别以xyz为关键字排三次序,再保留三次有序数列相邻两项之间的差值,即这两点之间的边权。在所得的3*(n-1)条边中可以保证满足kruskal对n-1条最短边的需求。为什么?显然法,可以意会。

#include<bits/stdc++.h>
using namespace std;

int n;
struct edge
{
    int x,y,z,i;
}e[100020];
struct edge2
{
    int x,y,v;
}a[900000];

long long summ=0;
int fa[100020];
int tott=0;

inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<3)+(x<<1)+s-48;
    x*=f;
}//可恨的快读啊

inline int find(int x){return(fa[x]==x?x:fa[x]=find(fa[x]));}

inline bool cmp1(edge a,edge b){return(a.x<b.x);}
inline bool cmp2(edge a,edge b){return(a.y<b.y);}
inline bool cmp3(edge a,edge b){return(a.z<b.z);}//xyz排序
inline bool mycmp(edge2 a,edge2 b){return(a.v<b.v);}

void sett()
{
    read(n);
    for(int i=1;i<=n;++i) 
    {
        read(e[i].x);read(e[i].y);read(e[i].z);e[i].i=i;
    }


    sort(e+1,e+n+1,cmp1);
    for(int i=2;i<=n;++i)
    {
        a[++tott].x=e[i-1].i;a[tott].y=e[i].i;a[tott].v=abs(e[i].x-e[i-1].x);
    }

    sort(e+1,e+n+1,cmp2);
    for(int i=2;i<=n;++i)
    {
        a[++tott].x=e[i-1].i;a[tott].y=e[i].i;a[tott].v=abs(e[i].y-e[i-1].y);
    }

    sort(e+1,e+n+1,cmp3);
    for(int i=2;i<=n;++i)
    {
        a[++tott].x=e[i-1].i;a[tott].y=e[i].i;a[tott].v=abs(e[i].z-e[i-1].z);
    }//三次排序。

    sort(a+1,a+tott+1,mycmp);//把得到的边升序排一遍。
}

void kru()
{   
    for(int i=1;i<=n;++i) fa[i]=i;
    int flag=0;
    for(int i=1;i<=tott;++i)
    {
        int x=find(a[i].x);
        int y=find(a[i].y);
        if(x!=y)
        {
            fa[x]=y;
            summ+=a[i].v;
            flag++;
            if(flag==n-1) return;
        }
    }
}//常规Kruskal。

int main()
{
    sett();
    kru();
    printf("%d",summ);
    return 0;
}

快读里判符号的f定义为bool了,跪了九个点,不能再说了,要落泪了。感谢ycy。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值