計蒜客一月入門賽 《三個火槍手》題解

2021-10-19 10:58:31 字數 3630 閱讀 1969

題目鏈結(

有 n 個人,其中有 m 對相互認識的關係。

乙個人的知名度定義為 有多少人 和他相互認識。

現在蒜頭君需要從這 n 個人中選出三個人成為火槍手,需要相互認識,但是在這個基礎上又希望他們三個人的知名度總和加起來最低。

輸入格式

第一行為兩個整數 n,m,都不大於 4000。

往後 m 行每一行輸入兩個不超過 n 的整數 x,y(x對於 50% 的資料,滿足 n,m<=200。

對於 100% 的資料,滿足 n,m≤4000。

輸出格式

如果能找到三個相互認識的人,你需要輸出所有選擇中 知名度總和的最低值,否則輸出 -1。

*輸出時每行末尾的多餘空格,不影響答案正確性

樣例輸入1

5 61 2

1 32 3

2 43 4

4 5樣例輸出1

8樣例輸入2

7 42 1

3 65 1

1 7樣例輸出2

-1題目**

計蒜客資訊學 1 月入門賽

首先我們看輸出的條件:三個相互認識的人知名度總和最低

接著搞清楚什麼是「三個相互認識的人」:由題目可知,輸入的x,y(x三個互相認識:也就是說,設三個人為1,2,3,若他們三個相互認識,就要輸入三次:①x=1,y=2 ②x=2,y=3 ③x=1,y=3.

然後搞清楚什麼是知名度總和最低

題目指出:乙個人的知名度定義為 有多少人 和他相互認識。

也就是說輸入一次x和y,x和y的知名度分別加1。

我們可以用個桶來統計。

但是有個特殊情況:資料中有可能會有重複的認識關係

之後再說處理方法。

注意:要審清題目:「如果能找到三個相互認識的人,你需要輸出所有選擇中 知名度總和的最低值,否則輸出 -1。」

意思就是:輸出三個互相認識的人中知名度總和的最低值而不能理解為如果三個知名度最小的人沒有都互相認識,就輸出-1。

用到統計,列舉,結構體,選擇排序等方法。

1.依照題目意思,暴力列舉o(n^3)

#include

using

namespace std;

#define size 5000

int a[size]

;struct gunsg[size]

;//我們可以用乙個結構體來統計乙個槍手的資訊,若g[x].f[y]>0則記x與y認識。

struct knowkn[size]

;//定義乙個結構體表示一組三個互相認識的人a,b,c

intmain()

//輸入加統計o(n)

//特殊情況處理:從guns入手 o(n^2)

for(

int i=

1;i<=n;i++

)for

(int j=

1;j<=n;j++)if

(g[i]

.f[j]

>

0) a[i]++;

//查詢三個互相認識的人o(n^3)暴力列舉

bool flag=0;

//標記有無三個互相認識的人

int top=0;

//指向kn的最後一組的下一位

for(

int i=

1;i<=n;i++

)for

(int j=i+

1;j<=n;j++

)for

(int k=j+

1;k<=n;k++)if

(g[i]

.f[j]

>

0&&g[j]

.f[k]

>

0&&g[i]

.f[k]

>0)

//沒有三個互相認識的人 if(

!flag)

//從三個互相認識的人組中篩出最小知名度

int min=a[kn[0]

.a]+a[kn[0]

.b]+a[kn[0]

.c];

for(

int i=

1;i) cout

}

能過5組資料,其餘超時。

我們從列舉的地方看看有什麼優化的地方。

要查詢三個互相認識的人可以嘗試從x和y入手。

因為x和y認識。

我引出了一種想法:

將所有x和y儲存到一起,比較x(xi)

1 2 0

1 3 1

2 3 2

2 4 3

3 4 4

4 5 5

它已經是有序的了。

先從i=1開始迴圈,若i=0時的a不等於i=1時的a(if(a[i]!=a[i-1])),就continue。

否則就是說明1認識2,1認識3,而此時只要判斷g[2].f[3]>0?就能得出三個互相認識的人了。

特殊情況:

a b1 2

1 31 4

2 32 4

3 44 5

此時,當i到達a=1,b=4時,則還需要多乙個迴圈判斷a=1,b=3和a=1,b=2的情況。

則這個想法的時間複雜度為o(n^2)

2.o(n^2)優化`

#include

#include

using

namespace std;

#define size 5000

int a[size]

;struct gunsg[size]

;//我們可以用乙個結構體來統計乙個槍手的資訊,若g[x].f[y]>0則記x與y認識。

struct xxyxy[size]

;//儲存x和y

struct knowkn[size]

;//定義乙個結構體表示一組三個互相認識的人a,b,c

intmain()

//輸入加統計o(n)

//特殊情況處理:從guns入手 o(n^2)

for(

int i=

1;i<=n;i++

)for

(int j=

1;j<=n;j++)if

(g[i]

.f[j]

>

0) a[i]++;

//給儲存xy的結構體排序,這裡用的是選擇排序

for(

int i=

0;iint top=0;

//查詢三個互相認識的人o(n^2)

bool flag=0;

//標記是否有三個互相認識的人

for(

int i=

1;i}//沒有三個互相認識的人 if(

!flag)

//從三個互相認識的人組中篩出最小知名度

int min=a[kn[0]

.a]+a[kn[0]

.b]+a[kn[0]

.c];

for(

int i=

1;i) cout

}

這樣就過了,不知道是不是可以用樹來解決,但是妹學。

計蒜客 5月入門賽 A B C D

計蒜客資訊學5月入門賽 題目要求不再敘述了 a 注意 資料型別 long long include includeusing namespace std define ll long long const int maxa 1e3 10 ll a,b,c,d int main b include i...

計蒜客2019 12提高組月賽

這道題目考察的主要是貪心的構造方法,唯一的難點就在於奇數的特殊處理 所以可以得到期望數量為 直接求個4的逆元一乘就做出來了 這道題目其實是樹上差分很常見的乙個思路 拆邊 想要快速的計算一些邊的和,我們把題目中的幸運邊在兩個點上 v,在兩點之間的路徑 v即可 然後就運用樹上差分實現求點權和邊權的和 i...

計蒜客 程式設計競賽入門

蒜頭的數學實在是太差了,於是老師把他關到小黑屋讓他閉門修煉。老師跟他一張紙,上面一排寫著1,2,3 n這n個數,中間用空白分隔。老師讓他在空白處填上加號或者減號。他讓蒜頭君求出一共有多少種加運算子的方法使得整個表示式的值為0,並輸出所有的方案。比如n 7時,1 2 3 4 5 6 7排成一排,一種插...