2019天梯賽第二次訓練賽


7-1 尋找250 (10 分)

對方不想和你說話,並向你扔了一串數…… 而你必須從這一串數字中找到“250”這個高大上的感人數字。

輸入格式:

輸入在一行中給出不知道多少個絕對值不超過1000的整數,其中保證至少存在一個“250”。

輸出格式:

在一行中輸出第一次出現的“250”是對方扔過來的第幾個數字(計數從1開始)。題目保證輸出的數字在整型范圍內。

輸入樣例:

888 666 123 -233 250 13 250 -222

輸出樣例:

5

水題

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int x,p=1,ac=-1;
 7     while(scanf("%d",&x)!=EOF)
 8     {
 9         if(x==250&&ac==-1)ac=p;
10         p++;
11     }
12     printf("%d\n",ac);
13     return 0;
14 }
7-2 日期格式化 (5 分)

世界上不同國家有不同的寫日期的習慣。比如美國人習慣寫成“月-日-年”,而中國人習慣寫成“年-月-日”。下面請你寫個程序,自動把讀入的美國格式的日期改寫成中國習慣的日期。

輸入格式:

輸入在一行中按照“mm-dd-yyyy”的格式給出月、日、年。題目保證給出的日期是1900年元旦至今合法的日期。

輸出格式:

在一行中按照“yyyy-mm-dd”的格式給出年、月、日。

輸入樣例:

03-15-2017

輸出樣例:

2017-03-15

水題

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int m,d,y;
 7     scanf("%d-%d-%d",&m,&d,&y);
 8     printf("%04d-%02d-%02d\n",y,m,d);
 9     return 0;
10 }
7-3 閱覽室 (20 分)

天梯圖書閱覽室請你編寫一個簡單的圖書借閱統計程序。當讀者借書時,管理員輸入書號並按下S鍵,程序開始計時;當讀者還書時,管理員輸入書號並按下E鍵,程序結束計時。書號為不超過1000的正整數。當管理員將0作為書號輸入時,表示一天工作結束,你的程序應輸出當天的讀者借書次數和平均閱讀時間。

注意:由於線路偶爾會有故障,可能出現不完整的紀錄,即只有S沒有E,或者只有E沒有S的紀錄,系統應能自動忽略這種無效紀錄。另外,題目保證書號是書的唯一標識,同一本書在任何時間區間內只可能被一位讀者借閱。

輸入格式:

輸入在第一行給出一個正整數N(10),隨后給出N天的紀錄。每天的紀錄由若干次借閱操作組成,每次操作占一行,格式為:

書號([1, 1000]內的整數) 鍵值SE發生時間hh:mm,其中hh是[0,23]內的整數,mm是[0, 59]內整數)

每一天的紀錄保證按時間遞增的順序給出。

輸出格式:

對每天的紀錄,在一行中輸出當天的讀者借書次數和平均閱讀時間(以分鍾為單位的精確到個位的整數時間)。

輸入樣例:

3
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00

輸出樣例:

2 196
0 0
1 60

小坑:當出現SSE的時候,得把第一個S忽視,因為它沒有E

四舍五入可以%.0f進行輸出

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int ti[1005];
 5 bool live[1005];
 6 int main()
 7 {
 8     int day,n=0,id,th,tm;
 9     int E=0,T=0;
10     char s[2];
11     scanf("%d",&day);
12     while(scanf("%d%s%d:%d",&id,s,&th,&tm)!=EOF)
13     {
14         if(id==0)
15         {
16             n++;
17             printf("%d %.0f\n",E,E==0?E:T*1./E);
18             E=0,T=0;
19             memset(live,false,sizeof live);
20             continue;
21         }
22         if(day==n)break;
23         if(s[0]=='S')//借書
24             ti[id]=th*60+tm,live[id]=true;
25         else if(s[0]=='E'&&live[id])//已借去還書
26             live[id]=false,E++,T+=th*60+tm-ti[id];
27     }
28     return 0;
29 }
7-4 穩贏 (15 分)

大家應該都會玩“錘子剪刀布”的游戲:兩人同時給出手勢,勝負規則如圖所示:

現要求你編寫一個穩贏不輸的程序,根據對方的出招,給出對應的贏招。但是!為了不讓對方輸得太慘,你需要每隔K次就讓一個平局。

輸入格式:

輸入首先在第一行給出正整數K10),即平局間隔的次數。隨后每行給出對方的一次出招:ChuiZi代表“錘子”、JianDao代表“剪刀”、Bu代表“布”。End代表輸入結束,這一行不要作為出招處理。

輸出格式:

對每一個輸入的出招,按要求輸出穩贏或平局的招式。每招占一行。

輸入樣例:

2
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
ChuiZi
End

輸出樣例:

Bu
ChuiZi
Bu
ChuiZi
JianDao
ChuiZi
Bu

當p為k+1的倍數時,需要平局

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int k,p=1;
 7     char s[10];
 8     scanf("%d",&k);
 9     while(scanf("%s",s)!=EOF)
10     {
11         if(s[0]=='E')break;
12         if(p%(k+1))
13         {
14             if(s[0]=='C')printf("Bu\n");
15             else if(s[0]=='J')printf("ChuiZi\n");
16             else if(s[0]=='B')printf("JianDao\n");
17         }
18         else
19         {
20             if(s[0]=='C')printf("ChuiZi\n");
21             else if(s[0]=='J')printf("JianDao\n");
22             else if(s[0]=='B')printf("Bu\n");
23         }
24         p++;
25     }
26     return 0;
27 }
7-5 宇宙無敵大招呼 (5 分)

據說所有程序員學習的第一個程序都是在屏幕上輸出一句“Hello World”,跟這個世界打個招呼。作為天梯賽中的程序員,你寫的程序得高級一點,要能跟任意指定的星球打招呼。

輸入格式:

輸入在第一行給出一個星球的名字S,是一個由不超過7個英文字母組成的單詞,以回車結束。

輸出格式:

在一行中輸出Hello S,跟輸入的S星球打個招呼。

輸入樣例:

Mars

輸出樣例:

Hello Mars

水題

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     string s;
 7     cin>>s;
 8     cout<<"Hello "<<s;
 9     return 0;
10 }
7-6 整除光棍 (20 分)

這里所謂的“光棍”,並不是指單身汪啦~ 說的是全部由1組成的數字,比如1、11、111、1111等。傳說任何一個光棍都能被一個不以5結尾的奇數整除。比如,111111就可以被13整除。 現在,你的程序要讀入一個整數x,這個整數一定是奇數並且不以5結尾。然后,經過計算,輸出兩個數字:第一個數字s,表示x乘以s是一個光棍,第二個數字n是這個光棍的位數。這樣的解當然不是唯一的,題目要求你輸出最小的解。

提示:一個顯然的辦法是逐漸增加光棍的位數,直到可以整除x為止。但難點在於,s可能是個非常大的數 —— 比如,程序輸入31,那么就輸出3584229390681和15,因為31乘以3584229390681的結果是111111111111111,一共15個1。

輸入格式:

輸入在一行中給出一個不以5結尾的正奇數x<1000)。

輸出格式:

在一行中輸出相應的最小的sn,其間以1個空格分隔。

輸入樣例:

31

輸出樣例:

3584229390681 15

模擬下大數除以小數,now/x為商

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

int main()
{
    int x,p=0,now=0,Len=0;
    scanf("%d",&x);
    while(++Len)
    {
        now=now*10+1;
        if(p||now/x)
            cout<<now/x,p=1;
        now%=x;
        if(now==0)
        {
            cout<<' '<<Len;
            break;
        }
    }
    return 0;
}
7-7 裝睡 (10 分)

你永遠叫不醒一個裝睡的人 —— 但是通過分析一個人的呼吸頻率和脈搏,你可以發現誰在裝睡!醫生告訴我們,正常人睡眠時的呼吸頻率是每分鍾15-20次,脈搏是每分鍾50-70次。下面給定一系列人的呼吸頻率與脈搏,請你找出他們中間有可能在裝睡的人,即至少一項指標不在正常范圍內的人。

輸入格式:

輸入在第一行給出一個正整數N10)。隨后N行,每行給出一個人的名字(僅由英文字母組成的、長度不超過3個字符的串)、其呼吸頻率和脈搏(均為不超過100的正整數)。

輸出格式:

按照輸入順序檢查每個人,如果其至少一項指標不在正常范圍內,則輸出其名字,每個名字占一行。

輸入樣例:

4
Amy 15 70
Tom 14 60
Joe 18 50
Zoe 21 71

輸出樣例:

Tom
Zoe

水題

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int n,a,b;
 7     char name[5];
 8     scanf("%d",&n);
 9     for(int i=0;i<n;i++)
10     {
11         scanf("%s%d%d",name,&a,&b);
12         if(a<15||20<a||b<50||70<b)printf("%s\n",name);
13     }
14     return 0;
15 }
7-8 矩陣A乘以B (15 分)

給定兩個矩陣AB,要求你計算它們的乘積矩陣AB。需要注意的是,只有規模匹配的矩陣才可以相乘。即若ARa行、Ca列,BRb行、Cb列,則只有CaRb相等時,兩個矩陣才能相乘。

輸入格式:

輸入先后給出兩個矩陣AB。對於每個矩陣,首先在一行中給出其行數R和列數C,隨后R行,每行給出C個整數,以1個空格分隔,且行首尾沒有多余的空格。輸入保證兩個矩陣的RC都是正數,並且所有整數的絕對值不超過100。

輸出格式:

若輸入的兩個矩陣的規模是匹配的,則按照輸入的格式輸出乘積矩陣AB,否則輸出Error: Ca != Rb,其中CaA的列數,RbB的行數。

輸入樣例1:

2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

輸出樣例1:

2 4
20 22 24 16
53 58 63 28

輸入樣例2:

3 2
38 26
43 -5
0 17
3 2
-11 57
99 68
81 72

輸出樣例2:

Error 2 != 3

矩陣A naXnb

矩陣B maXmb

矩陣C naXnb*maXmb = naXmb(當且僅當nb==ma)

三層循環,第一層C的na,第二層C的mb,第三層ma或者nb

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[105][105],b[105][105],c[105][105];
 5 int main()
 6 {
 7     int na,ma,nb,mb;
 8     scanf("%d%d",&na,&nb);
 9     for(int i=1;i<=na;i++)
10         for(int j=1;j<=nb;j++)
11             scanf("%d",&a[i][j]);
12     scanf("%d%d",&ma,&mb);
13     for(int i=1;i<=ma;i++)
14         for(int j=1;j<=mb;j++)
15             scanf("%d",&b[i][j]);
16     if(nb!=ma)printf("Error: %d != %d\n",nb,ma);
17     else
18     {
19         for(int i=1;i<=na;i++)
20             for(int j=1;j<=mb;j++)
21                 for(int k=1;k<=ma;k++)
22                     c[i][j]+=a[i][k]*b[k][j];
23         printf("%d %d\n",na,mb);
24         for(int i=1;i<=na;i++)
25             for(int j=1;j<=mb;j++)
26                 printf("%d%c",c[i][j],j==mb?'\n':' ');
27     }
28     return 0;
29 }
7-9 點贊狂魔 (25 分)

微博上有個“點贊”功能,你可以為你喜歡的博文點個贊表示支持。每篇博文都有一些刻畫其特性的標簽,而你點贊的博文的類型,也間接刻畫了你的特性。然而有這么一種人,他們會通過給自己看到的一切內容點贊來狂刷存在感,這種人就被稱為“點贊狂魔”。他們點贊的標簽非常分散,無法體現出明顯的特性。本題就要求你寫個程序,通過統計每個人點贊的不同標簽的數量,找出前3名點贊狂魔。

輸入格式:

輸入在第一行給出一個正整數N100),是待統計的用戶數。隨后N行,每行列出一位用戶的點贊標簽。格式為“Name K F1FK”,其中Name是不超過8個英文小寫字母的非空用戶名,1K1000Fii=1,,K)是特性標簽的編號,我們將所有特性標簽從 1 到 107 編號。數字間以空格分隔。

輸出格式:

統計每個人點贊的不同標簽的數量,找出數量最大的前3名,在一行中順序輸出他們的用戶名,其間以1個空格分隔,且行末不得有多余空格。如果有並列,則輸出標簽出現次數平均值最小的那個,題目保證這樣的用戶沒有並列。若不足3人,則用-補齊缺失,例如mike jenny -就表示只有2人。

輸入樣例:

5
bob 11 101 102 103 104 105 106 107 108 108 107 107
peter 8 1 2 3 4 3 2 5 1
chris 12 1 2 3 4 5 6 7 8 9 1 2 3
john 10 8 7 6 5 4 3 2 1 7 5
jack 9 6 7 8 9 10 11 12 13 14

輸出樣例:

jack chris john

結構體排序一下就行,判重用set

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct p
 5 {
 6     char name[15];
 7     int cnt;
 8     double ave;
 9 }d[105];
10 bool cmp(p a,p b)
11 {
12     if(a.cnt!=b.cnt)return a.cnt>b.cnt;
13     return a.ave<b.ave;
14 }
15 int main()
16 {
17     int n,k;
18     set<int>s;
19     scanf("%d",&n);
20     for(int i=0;i<n;i++)
21     {
22         scanf("%s%d",d[i].name,&k);
23         for(int j=0;j<k;j++)
24         {
25             int v;
26             scanf("%d",&v);
27             s.insert(v);
28         }
29         d[i].cnt=s.size();
30         d[i].ave=k*1./(int)s.size();
31         s.clear();
32     }
33     sort(d,d+n,cmp);
34     for(int i=0;i<3;i++)
35     {
36         if(i!=0)printf(" ");
37         if(i<n)printf("%s",d[i].name);
38         else printf("-");
39     }
40     return 0;
41 }
7-10 重排鏈表 (25 分)

給定一個單鏈表 L1L2Ln1Ln,請編寫程序將鏈表重新排列為 LnL1Ln1L2。例如:給定L為1→2→3→4→5→6,則輸出應該為6→1→5→2→4→3。

輸入格式:

每個輸入包含1個測試用例。每個測試用例第1行給出第1個結點的地址和結點總個數,即正整數N (105)。結點的地址是5位非負整數,NULL地址用1表示。

接下來有N行,每行格式為:

Address Data Next

其中Address是結點地址;Data是該結點保存的數據,為不超過105的正整數;Next是下一結點的地址。題目保證給出的鏈表上至少有兩個結點。

輸出格式:

對每個測試用例,順序輸出重排后的結果鏈表,其上每個結點占一行,格式與輸入相同。

輸入樣例:

00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

輸出樣例:

68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1

先建一個鏈表,注意會有多余節點(無用),輸出的時候一左一右,兩行兩行輸出,最后判斷一下奇偶,奇數就輸出最后一行,偶數輸出最后兩行

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e5+5;
 5 struct Node
 6 {
 7     int u,v,w;
 8 }a[maxn];
 9 vector<Node>G;
10 int main()
11 {
12     int s,k,u,v,w;
13     scanf("%d%d",&s,&k);
14     for(int i=0;i<k;i++)
15     {
16         scanf("%d%d%d",&u,&w,&v);
17         a[u]={u,v,w};
18     }
19     int cnt=0;
20     while(1)
21     {
22         G.push_back(a[s]);
23         s=a[s].v;
24         cnt++;
25         if(s==-1)break;
26     }
27     int L=0,R=cnt-1;
28     while(L<=R)
29     {
30         printf("%05d %d %05d\n",G[R].u,G[R].w,G[L].u);
31         printf("%05d %d ",G[L].u,G[L].w);
32         L++,R--;
33         if(L==R)
34         {
35             //剩一個
36             printf("%05d\n%05d %d -1\n",G[R].u,G[R].u,G[R].w);
37             break;
38         }
39         else
40         {
41             if(L<cnt/2)//不是最后倆個
42                 printf("%05d\n",G[R].u);
43             else//最后倆個
44             {
45                 printf("-1\n");
46                 break;
47             }
48         }
49     }
50     return 0;
51 }
7-11 圖着色問題 (25 分)

圖着色問題是一個著名的NP完全問題。給定無向圖G=(V,E),問可否用K種顏色為V中的每一個頂點分配一種顏色,使得不會有兩個相鄰頂點具有同一種顏色?

但本題並不是要你解決這個着色問題,而是對給定的一種顏色分配,請你判斷這是否是圖着色問題的一個解。

輸入格式:

輸入在第一行給出3個整數V0<V500)、E0)和K0<KV),分別是無向圖的頂點數、邊數、以及顏色數。頂點和顏色都從1到V編號。隨后E行,每行給出一條邊的兩個端點的編號。在圖的信息給出之后,給出了一個正整數N20),是待檢查的顏色分配方案的個數。隨后N行,每行順次給出V個頂點的顏色(第i個數字表示第i個頂點的顏色),數字間以空格分隔。題目保證給定的無向圖是合法的(即不存在自回路和重邊)。

輸出格式:

對每種顏色分配方案,如果是圖着色問題的一個解則輸出Yes,否則輸出No,每句占一行。

輸入樣例:

6 8 3
2 1
1 3
4 6
2 5
2 4
5 4
5 6
3 6
4
1 2 3 3 1 2
4 5 6 6 4 5
1 2 3 4 5 6
2 3 4 2 3 4

輸出樣例:

Yes
Yes
No
No

點數很少,可以直接暴力找連邊是否顏色相同,N個詢問復雜度(N*V^2)不高可以通過,這里用set判顏色數量,顏色數量剛好為K才可以

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 bool G[505][505];
 5 int color[505];
 6 int main()
 7 {
 8     int v,e,k,uu,vv;
 9     scanf("%d%d%d",&v,&e,&k);
10     for(int i=0;i<e;i++)
11     {
12         scanf("%d%d",&uu,&vv);
13         G[uu][vv]=G[vv][uu]=true;
14     }
15     int n;
16     scanf("%d",&n);
17     while(n--)
18     {
19         set<int>s;
20         for(int i=1;i<=v;i++)
21         {
22             scanf("%d",&color[i]);
23             s.insert(color[i]);
24         }
25         int flag=1;
26         if(s.size()!=k)flag=0;
27         else
28         {
29             for(int i=1;i<=v;i++)
30             {
31                 for(int j=1;j<=v;j++)
32                 {
33                     if(G[i][j]&&i!=j&&color[i]==color[j])
34                     {
35                         flag=0;
36                         break;
37                     }
38                 }
39                 if(flag==0)break;
40             }
41         }
42         if(flag)printf("Yes\n");
43         else printf("No\n");
44     }
45     return 0;
46 }
7-12 部落 (25 分)

在一個社區里,每個人都有自己的小圈子,還可能同時屬於很多不同的朋友圈。我們認為朋友的朋友都算在一個部落里,於是要請你統計一下,在一個給定社區中,到底有多少個互不相交的部落?並且檢查任意兩個人是否屬於同一個部落。

輸入格式:

輸入在第一行給出一個正整數N104),是已知小圈子的個數。隨后N行,每行按下列格式給出一個小圈子里的人:

K P[1] P[2] P[K]

其中K是小圈子里的人數,P[i]i=1,,K)是小圈子里每個人的編號。這里所有人的編號從1開始連續編號,最大編號不會超過104

之后一行給出一個非負整數Q104),是查詢次數。隨后Q行,每行給出一對被查詢的人的編號。

輸出格式:

首先在一行中輸出這個社區的總人數、以及互不相交的部落的個數。隨后對每一次查詢,如果他們屬於同一個部落,則在一行中輸出Y,否則輸出N

輸入樣例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

輸出樣例:

10 2
Y
N

並查集模板題

find(x) 找x的父親,並且壓縮路徑(再以后查找的時候會變快),比如1-3-4會變成1-4

join 連通a和b

初始化f[i]=i

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1e4+5;
 5 int f[maxn];
 6 int find(int x)
 7 {
 8     return f[x]==x?x:f[x]=find(f[x]);
 9 }
10 void join(int a,int b)
11 {
12     f[find(a)]=find(b);
13 }
14 int main()
15 {
16     int n,u,v,q,ans=0,maxx=0;
17     scanf("%d",&n);
18     for(int i=1;i<=10000;i++)f[i]=i;
19     for(int i=1;i<=n;i++)
20     {
21         int k,u,v;
22         scanf("%d",&k);
23         if(k>=1)scanf("%d",&u),maxx=max(maxx,u);
24         for(int j=2;j<=k;j++)
25         {
26             scanf("%d",&v),maxx=max(maxx,v);
27             join(u,v);
28         }
29     }
30     for(int i=1;i<=maxx;i++)
31         if(f[i]==i)
32             ans++;
33     printf("%d %d\n",maxx,ans);
34     scanf("%d",&q);
35     for(int i=0;i<q;i++)
36     {
37         int u,v;
38         scanf("%d%d",&u,&v);
39         if(find(u)==find(v))printf("Y\n");
40         else printf("N\n");
41     }
42     return 0;
43 }
7-13 二叉搜索樹的結構 (30 分)

二叉搜索樹或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;它的左、右子樹也分別為二叉搜索樹。(摘自百度百科)

給定一系列互不相等的整數,將它們順次插入一棵初始為空的二叉搜索樹,然后對結果樹的結構進行描述。你需要能判斷給定的描述是否正確。例如將{ 2 4 1 3 0 }插入后,得到一棵二叉搜索樹,則陳述句如“2是樹的根”、“1和4是兄弟結點”、“3和0在同一層上”(指自頂向下的深度相同)、“2是4的雙親結點”、“3是4的左孩子”都是正確的;而“4是2的左孩子”、“1和3是兄弟結點”都是不正確的。

輸入格式:

輸入在第一行給出一個正整數N100),隨后一行給出N個互不相同的整數,數字間以空格分隔,要求將之順次插入一棵初始為空的二叉搜索樹。之后給出一個正整數M100),隨后M行,每行給出一句待判斷的陳述句。陳述句有以下6種:

  • A is the root,即"A是樹的根";
  • A and B are siblings,即"AB是兄弟結點";
  • A is the parent of B,即"AB的雙親結點";
  • A is the left child of B,即"AB的左孩子";
  • A is the right child of B,即"AB的右孩子";
  • A and B are on the same level,即"AB在同一層上"。

題目保證所有給定的整數都在整型范圍內。

輸出格式:

對每句陳述,如果正確則輸出Yes,否則輸出No,每句占一行。

輸入樣例:

5
2 4 1 3 0
8
2 is the root
1 and 4 are siblings
3 and 0 are on the same level
2 is the parent of 4
3 is the left child of 4
1 is the right child of 2
4 and 0 are on the same level
100 is the right child of 3

輸出樣例:

Yes
Yes
Yes
Yes
Yes
No
No
No

時隔1年的時間再來做這個題,當時170行搜索樹上搜搜搜,現在120行DFS一便記錄所有信息,有所進步(霧)

建搜索樹還是老樣子,鏈表

建完后,DFS(root,fa)root為根節點,fa為雙親節點

每個數字用map<int,int>ma,cnt=1進行哈希存儲,map在int下若不存在值為0

每個節點信息存fa雙親節點,sonl左兒子,sonr右兒子,level層數

詢問的時候,前提條件是詢問的節點都存在即map[A]>0||map[B]>0

1.A根:root->data為A

2.A和B兄弟:父母一樣

3.A是B的雙親:B的雙親為A

4.A是B左兒子:B的左兒子為A

5.A是B右兒子:B的右兒子為A

6.A和B同一層:層數相同

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 struct Node
  4 {
  5     int data;
  6     Node *Left,*Right;
  7     Node():data(-1),Left(NULL),Right(NULL){}
  8 };
  9 Node *addnode(){return new Node();}
 10 Node *root;
 11 int cnt=0;
 12 map<int,int>ma;
 13 void Create(Node *u,int a)
 14 {
 15     if(u->data==-1)
 16     {
 17         u->data=a;
 18         return ;
 19     }
 20     else
 21     {
 22         if(a>u->data)
 23         {
 24             if(u->Right==NULL)
 25                 u->Right=addnode();
 26             Create(u->Right,a);
 27         }
 28         else
 29         {
 30             if(u->Left==NULL)
 31                 u->Left=addnode();
 32             Create(u->Left,a);
 33         }
 34     }
 35 }
 36 struct message
 37 {
 38     int fa;
 39     int sonl,sonr;
 40     int level;
 41 }d[105];
 42 void dfs(Node *u,Node *fa,int level)
 43 {
 44     if(u==NULL)return;
 45     int val=u->data;
 46     int pos=ma[val];
 47     if(fa!=NULL)
 48         d[pos].fa=fa->data;
 49     if(u->Left!=NULL)
 50         d[pos].sonl=u->Left->data;
 51     if(u->Right!=NULL)
 52         d[pos].sonr=u->Right->data;
 53     d[pos].level=level;
 54     dfs(u->Left,u,level+1);
 55     dfs(u->Right,u,level+1);
 56 }
 57 int main()
 58 {
 59     root=addnode();
 60     int n,m;
 61     scanf("%d",&n);
 62     for(int i=1,u;i<=n;i++)
 63     {
 64         scanf("%d",&u);
 65         if(ma[u]==0)ma[u]=++cnt;
 66         Create(root,u);
 67     }
 68     dfs(root,NULL,1);
 69     scanf("%d",&m);
 70     string s;
 71     int A,B;
 72     while(m--)
 73     {
 74         cin>>A>>s;
 75         int posA=ma[A];
 76         int posB;
 77         int flag=0;
 78         if(s=="is")
 79         {
 80             cin>>s>>s;
 81             if(s=="root")//1
 82             {
 83                 if(root->data==A)flag=1;
 84             }
 85             else if(s=="parent")//3
 86             {
 87                 cin>>s>>B;
 88                 posB=ma[B];
 89                 if(d[posB].fa==A)flag=1;
 90             }
 91             else if(s=="left")//4
 92             {
 93                 cin>>s>>s>>B;
 94                 posB=ma[B];
 95                 if(d[posB].sonl==A)flag=1;
 96             }
 97             else if(s=="right")//5
 98             {
 99                 cin>>s>>s>>B;
100                 posB=ma[B];
101                 if(d[posB].sonr==A)flag=1;
102             }
103         }
104         else if(s=="and")
105         {
106             cin>>B>>s>>s;
107             posB=ma[B];
108             if(s=="siblings")//2
109             {
110                 if(d[posA].fa==d[posB].fa)flag=1;
111             }
112             else if(s=="on")//6
113             {
114                 cin>>s>>s>>s;
115                 if(d[posA].level==d[posB].level)flag=1;
116             }
117         }
118         if(posA==0||posB==0)flag=0;
119         printf("%s\n",flag?"Yes":"No");
120     }
121     return 0;
122 }
7-14 森森快遞 (30 分)

森森開了一家快遞公司,叫森森快遞。因為公司剛剛開張,所以業務路線很簡單,可以認為是一條直線上的N個城市,這些城市從左到右依次從0到(N1)編號。由於道路限制,第i號城市(i=0,,N2)與第(i+1)號城市中間往返的運輸貨物重量在同一時刻不能超過Ci公斤。

公司開張后很快接到了Q張訂單,其中j張訂單描述了某些指定的貨物要從Sj號城市運輸到Tj號城市。這里我們簡單地假設所有貨物都有無限貨源,森森會不定時地挑選其中一部分貨物進行運輸。安全起見,這些貨物不會在中途卸貨。

為了讓公司整體效益更佳,森森想知道如何安排訂單的運輸,能使得運輸的貨物重量最大且符合道路的限制?要注意的是,發貨時間有可能是任何時刻,所以我們安排訂單的時候,必須保證共用同一條道路的所有貨車的總重量不超載。例如我們安排1號城市到4號城市以及2號城市到4號城市兩張訂單的運輸,則這兩張訂單的運輸同時受2-3以及3-4兩條道路的限制,因為兩張訂單的貨物可能會同時在這些道路上運輸。

輸入格式:

輸入在第一行給出兩個正整數NQ2N105, 1Q105),表示總共的城市數以及訂單數量。

第二行給出(N1)個數,順次表示相鄰兩城市間的道路允許的最大運貨重量Cii=0,,N2)。題目保證每個Ci是不超過231的非負整數。

接下來Q行,每行給出一張訂單的起始及終止運輸城市編號。題目保證所有編號合法,並且不存在起點和終點重合的情況。

輸出格式:

在一行中輸出可運輸貨物的最大重量。

輸入樣例:

10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2

輸出樣例:

7

樣例提示:我們選擇執行最后兩張訂單,即把5公斤貨從城市4運到城市2,並且把2公斤貨從城市4運到城市5,就可以得到最大運輸量7公斤。

貪心+線段樹區間更新

貪心處理區間A[l,r]和B[L,R],這里已經按右端點從小到大排序了:

1.A和B區間不相交 不影響 假設取A

2.A完全包含於B   A在里面,先取B的話,會對后面的C產生影響,所以得取A

3.A和B相交 假設先取B,那么會影響到A的取值,取A的影響小

A的r和B的R相同怎么取,情況1:B包含於A,因為影響的已經搞掉了,取A取B一樣。情況2:AB不交,取A取B一樣

所以按照右端點從小到大排就行

然后就是愉快的線段樹區間lazy標記,比較模板,注意得開LL

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define LL long long
 5 const int maxn=1e5+5;
 6 LL minn[maxn<<2],lazy[maxn<<2];
 7 int n,q;
 8 void build(int l,int r,int rt)
 9 {
10     if(l==r)
11     {
12         if(l>1)scanf("%lld",&minn[rt]);
13         else minn[r]=(1LL<<31);
14         return;
15     }
16     int mid=(l+r)>>1;
17     build(l,mid,rt<<1);
18     build(mid+1,r,rt<<1|1);
19     minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
20 }
21 void pushdown(int rt)
22 {
23     if(lazy[rt]==0)return;
24     lazy[rt<<1]+=lazy[rt];
25     lazy[rt<<1|1]+=lazy[rt];
26     minn[rt<<1]+=lazy[rt];
27     minn[rt<<1|1]+=lazy[rt];
28     lazy[rt]=0;
29 }
30 LL query(int L,int R,int l,int r,int rt)
31 {
32     if(L<=l&&r<=R)return minn[rt];
33     int mid=(l+r)>>1;
34     LL ans=(1LL<<31);
35     pushdown(rt);
36     if(L<=mid)ans=min(ans,query(L,R,l,mid,rt<<1));
37     if(R>mid)ans=min(ans,query(L,R,mid+1,r,rt<<1|1));
38     minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
39     return ans;
40 }
41 void update(int L,int R,LL C,int l,int r,int rt)
42 {
43     if(L<=l&&r<=R)
44     {
45         minn[rt]+=C;
46         lazy[rt]+=C;
47         return;
48     }
49     int mid=(l+r)>>1;
50     pushdown(rt);
51     if(L<=mid)update(L,R,C,l,mid,rt<<1);
52     if(R>mid)update(L,R,C,mid+1,r,rt<<1|1);
53     minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
54 }
55 struct p
56 {
57     int s,e;
58 }d[maxn];
59 bool cmp(p a,p b)
60 {
61     return a.s<b.s||(a.s==b.s&&a.e<b.e);
62 }
63 int main()
64 {
65     memset(minn,0x3f,sizeof minn);
66     scanf("%d%d",&n,&q);
67     build(1,n,1);
68     for(int i=0;i<q;i++)
69     {
70         scanf("%d%d",&d[i].s,&d[i].e),d[i].s++,d[i].e++;
71         if(d[i].s>d[i].e)swap(d[i].s,d[i].e);
72     }
73     sort(d,d+q,cmp);
74     LL ans=0;
75     for(int i=0;i<q;i++)
76     {
77         int L=d[i].s,R=d[i].e;
78         if(L==R)continue;
79         LL minn=query(L+1,R,1,n,1);
80         update(L+1,R,-minn,1,n,1);
81         ans+=minn;
82     }
83     printf("%lld\n",ans);
84     return 0;
85 }
7-15 森森美圖 (30 分)

森森最近想讓自己的朋友圈熠熠生輝,所以他決定自己寫個美化照片的軟件,並起名為森森美圖。眾所周知,在合照中美化自己的面部而不美化合照者的面部是讓自己占據朋友圈高點的絕好方法,因此森森美圖里當然得有這個功能。 這個功能的第一步是將自己的面部選中。森森首先計算出了一個圖像中所有像素點與周圍點的相似程度的分數,分數越低表示某個像素點越“像”一個輪廓邊緣上的點。 森森認為,任意連續像素點的得分之和越低,表示它們組成的曲線和輪廓邊緣的重合程度越高。為了選擇出一個完整的面部,森森決定讓用戶選擇面部上的兩個像素點A和B,則連接這兩個點的直線就將圖像分為兩部分,然后在這兩部分中分別尋找一條從A到B且與輪廓重合程度最高的曲線,就可以拼出用戶的面部了。 然而森森計算出來得分矩陣后,突然發現自己不知道怎么找到這兩條曲線了,你能幫森森當上朋友圈的小王子嗎?

為了解題方便,我們做出以下補充說明:

  • 圖像的左上角是坐標原點(0,0),我們假設所有像素按矩陣格式排列,其坐標均為非負整數(即橫軸向右為正,縱軸向下為正)。
  • 忽略正好位於連接A和B的直線(注意不是線段)上的像素點,即不認為這部分像素點在任何一個划分部分上,因此曲線也不能經過這部分像素點。
  • 曲線是八連通的(即任一像素點可與其周圍的8個像素連通),但為了計算准確,某像素連接對角相鄰的斜向像素時,得分額外增加兩個像素分數和的2倍減一。例如樣例中,經過坐標為(3,1)和(4,2)的兩個像素點的曲線,其得分應該是這兩個像素點的分數和(2+2),再加上額外的(2+2)乘以(21),即約為5.66。

輸入格式:

輸入在第一行給出兩個正整數NM5N,M100),表示像素得分矩陣的行數和列數。

接下來N行,每行M個不大於1000的非負整數,即為像素點的分值。

最后一行給出用戶選擇的起始和結束像素點的坐標(Xstart,Ystart)(Xend,Yend)。4個整數用空格分隔。

輸出格式:

在一行中輸出划分圖片后找到的輪廓曲線的得分和,保留小數點后兩位。注意起點和終點的得分不要重復計算。

輸入樣例:

6 6
9 0 1 9 9 9
9 9 1 2 2 9
9 9 2 0 2 9
9 9 1 1 2 9
9 9 3 3 1 1
9 9 9 9 9 9
2 1 5 4

輸出樣例:

27.04

首先怎么判斷在直線兩側

考慮叉積,如果叉積(A,B,C)>0,說明AB在AC逆時針方向,<0順時針,=0重合

直線中的兩點A和B,叉積(A,B,C)>0說明在直線左邊

直線右邊就是叉積(B,A,C)>0

那么問題就變成最短路

注意如果斜着走是額外加兩個值*(sqrt(2)-1)

然后從A跑到B(左側),再從B跑到A(由於叉積判左側,倒着來就是在右側),最后減去多算的A點和B點的值

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

double sc[110][110];
int dx[]={1,-1,0,0,1,-1,1,-1};
int dy[]={0,0,1,-1,1,-1,-1,1};
struct p
{
    int x,y;
}l,r;
int cross(p a,p b,p c)
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double ans[110][110];
int n,m;
double bfs(p s,p e)
{
    for(int i=0;i<=105;i++)
        for(int j=0;j<=105;j++)
            ans[i][j]=1e18;
    p u,t,a=s,b=e;
    queue<p>q;
    while(!q.empty())q.pop();
    q.push(s);
    ans[s.x][s.y]=sc[s.x][s.y];
    while(!q.empty())
    {
        u=q.front();q.pop();
        for(int i=0;i<8;i++)
        {
            t.x=u.x+dx[i];
            t.y=u.y+dy[i];
            if((cross(a,b,t)>0||(t.x==e.x&&t.y==e.y))&&t.x>=0&&t.x<n&&t.y>=0&&t.y<m)
            {
                double w=sc[t.x][t.y];
                if(i>3)w+=(sc[t.x][t.y]+sc[u.x][u.y])*(sqrt(2.)-1);
                if(ans[t.x][t.y]>ans[u.x][u.y]+w)
                {
                    ans[t.x][t.y]=ans[u.x][u.y]+w;
                    q.push(t);
                }
            }
        }
    }
    return ans[e.x][e.y];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%lf",&sc[i][j]);
    scanf("%d%d%d%d",&l.y,&l.x,&r.y,&r.x);
    printf("%.2f\n",bfs(l,r)+bfs(r,l)-sc[l.x][l.y]-sc[r.x][r.y]);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM