天天看點

12/28 圖論搜尋測試總結T1 促銷T2 特殊字典序T3 星級隧道

真的跪了

時間配置設定極欠妥當。心态不穩定,處于“暴力寫不好”“正解沒時間寫”的絕妙境地。

會建圖,反而是算法的具體實施很不熟練。細節處欠缺太多。

多自主思考。

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=;
int ans=;
double a=;

void dfs(int step,double summ,int x)
{
    if(step==n) {
        if(abs(summ-a)<=) ans++;//誤差在一定範圍内可接受,即為一解。
        return;
    }
    if(summ-a>) return;//可行性剪枝。
    for(int i=x+;i<=m;++i)//最優化剪枝。
        dfs(step+,summ+/i,i);
}

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

涉及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的代碼:

12/28 圖論搜尋測試總結T1 促銷T2 特殊字典序T3 星級隧道
12/28 圖論搜尋測試總結T1 促銷T2 特殊字典序T3 星級隧道

就是活生生的裸的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[];
struct edge2
{
    int x,y,v;
}a[];

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

inline void read(int &x)
{
    int f=;x=;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<)+(x<<)+s-;
    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=;i<=n;++i) 
    {
        read(e[i].x);read(e[i].y);read(e[i].z);e[i].i=i;
    }


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

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

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

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

void kru()
{   
    for(int i=;i<=n;++i) fa[i]=i;
    int flag=;
    for(int i=;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-) return;
        }
    }
}//正常Kruskal。

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

快讀裡判符号的f定義為bool了,跪了九個點,不能再說了,要落淚了。感謝ycy。