1、二叉樹(binary)

1.二叉樹 (binary.cpp/c/pas) 【問題描述】 二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹: (1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; (2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; (3)左、右子樹也分別為二叉排序樹; (4)沒有鍵值相等的結點。 完全二叉樹:只有最下面的兩層結點度能夠小於2,並且最下面一層的結點 都集中在該層最左邊的若干位置的二叉樹。 圖1中,(a)和(b)是完全二叉樹,(c)和(d)是非完全二叉樹。 給出N個數,且這N個數構成1至N的排列。現在需要你按順序構建一棵二叉 排序樹,並按照層次遍歷的方式輸出它,然后判斷它是否是一棵完全二叉樹。 【輸入格式】 輸入文件名為binary.in。 輸入文件包含兩行。第一行為一個正整數N;第二行為1至N的排列。 【輸出格式】 輸出文件名為binary.out。 輸出文件包含兩行。第一行為構建出的二叉排序樹的層次遍歷;第二行判 斷是否是完全二叉樹:若是輸出yes,否則輸出no。 【輸入輸出樣例1】 binary.in 10 7 9 8 4 6 2 10 1 5 3 binary.out 7 4 9 2 6 8 10 1 3 5 yes 【輸入輸出樣例2】 binary.in 5 3 4 5 2 1 binary.out 3 2 4 1 5 no 【數據規模與約定】 對於100%的數據,1≤N≤20。
tag:模擬
思路:其實這道題沒有看上去那么復雜。插入的時候比節點大就往右走,反之往左走,走到頭了放進去,最后建個樹。判斷是不是完全二叉樹要看最大的節點是不是在自己應該在的位置,因為仔細觀察發現完全二叉樹是每一層從左往右一個一個放,每個節點的數值和編號應該相等(感謝dalao這句話的思路)。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 int maxx,list[30][30],tree[1<<21],deep,n; 8 void insert(int o,int x) 9 { 10 maxx=max(maxx,o); 11 if(!tree[o]){ 12 tree[o]=x; 13 return; 14 } 15 if(x>tree[o]) insert(o<<1|1,x); 16 else insert(o<<1,x); 17 } 18 void dfs(int o,int f) 19 { 20 deep=max(deep,f); 21 if(tree[o<<1]){ 22 list[f+1][++list[f+1][0]]=tree[o<<1]; 23 dfs(o<<1,f+1); 24 } 25 if(tree[o<<1|1]){ 26 list[f+1][++list[f+1][0]]=tree[o<<1|1]; 27 dfs(o<<1|1,f+1); 28 } 29 } 30 int main() 31 { 32 //freopen("binary.in","r",stdin); 33 //freopen("binary.out","w",stdout); 34 int x; 35 scanf("%d",&n); 36 for(int i=1;i<=n;++i){ 37 scanf("%d",&x); 38 insert(1,x); 39 } 40 list[1][1]=tree[1]; 41 list[1][0]=1; 42 dfs(1,1); 43 for(int i=1;i<=deep;++i) 44 for(int j=1;j<=list[i][0];++j) 45 printf("%d ",list[i][j]); 46 puts(""); 47 if(maxx!=n) puts("no"); 48 else puts("yes"); 49 return 0; 50 }
2、列車調度(manage)

【問題描述】 有N輛列車,標記為1,2,3,…,N。它們按照一定的次序進站,站台共有K個軌 道,軌道遵從先進先出的原則。列車進入站台內的軌道后可以等待任意時間后出 站,且所有列車不可后退。現在要使出站的順序變為N,N-1,N-2,…,1,詢問K的 最小值是多少。 例如上圖中進站的順序為1,3,2,4,8,6,9,5,7,則出站的順序變為 9,8,7,6,5,4,3,2,1。 【輸入格式】 輸入文件名為manage.in。 輸入共2行。 第 1 行包含1個正整數N,表示N輛列車。 第 2 行包含N個正整數,為1至N的一個排列,表示進站次序。 【輸出格式】 輸出文件名為manage.out。 輸出共1行,包含1個整數,表示站台內軌道數K的最小值。 【輸入輸出樣例1】 manage.in 3 1 2 3 manage.out 3 【輸入輸出樣例2】 manage.in 9 1 3 2 4 8 6 9 5 7 manage.out 5 【數據規模與約定】 對於 30%的數據,N≤10; 對於 70%的數據,N≤2000; 對於 100%的數據,N≤100000。
tag:二分查找
思路:單純模擬用時較長(但是O(n2)居然能過???),正解是構造非降序列,比如現在的序列是(5,6,9,11),要把10插入進去,5,6,9都比10小,11比10大就停在11后面,序列變成(5,6,9,10),雖然單個的數值改變了,但是原本的單調性沒變,因此我們可以二分查找第一個比要插入的數大的數(0011型)。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<cstdlib> 7 #define maxn 100010 8 using namespace std; 9 int n,a[maxn],f[maxn],ans=1; 10 int main() 11 { 12 //freopen("manage.in","r",stdin); 13 //freopen("manage.out","w",stdout); 14 scanf("%d",&n); 15 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 16 f[1]=a[1]; 17 for(int i=2;i<=n;++i){ 18 int l=lower_bound(f+1,f+ans+1,a[i])-f; 19 f[l]=a[i]; 20 ans=max(ans,l); 21 } 22 printf("%d",ans); 23 return 0; 24 }
3、保留道路(road)

【問題描述】 很久很久以前有一個國家,這個國家有N個城市,城市由1,2,3,…,N標號, 城市間有M條雙向道路,每條道路都有兩個屬性g和s,兩個城市間可能有多條道 路,並且可能存在將某一城市與其自身連接起來的道路。后來由於戰爭的原因, 國王不得不下令減小花費從而關閉一些道路,但是必須要保證任意兩個城市相互 可達。 道路花費的計算公式為wG*max{所有剩下道路的屬性g}+wS*max{所有剩下道 路的屬性s},其中wG和wS是給定的值。國王想要在滿足連通性的前提下使這個花 費最小,現在需要你計算出這個花費。 【輸入格式】 輸入文件名為road.in。 第一行包含兩個正整數N和M。 第二行包含兩個正整數wG和wS。 后面的M行每行描述一條道路,包含四個正整數u,v,g,s,分別表示道路連接 的兩個城市以及道路的兩個屬性。 【輸出格式】 輸出文件名為road.out。 輸出一個整數,表示最小花費。若無論如何不能滿足連通性,輸出-1。 【輸入輸出樣例】 road.in 3 3 2 1 1 2 10 15 1 2 4 20 1 3 5 1 road.out 30 【數據規模與約定】 對於 10%的數據,N≤10,M≤20; 對於 30%的數據,N≤100,M≤1000; 對於 50%的數據,N≤200,M≤5000; 對於 100%的數據,N≤400,M≤50000,wG,wS,g,s≤1000000000。
tag:最小生成樹、輕度玄學(霧)
思路:二維費用的kruskal,很有研究的價值。平時我們做的最小生成樹都只有一維,突然多了一個維度,而且還有系數,有點讓人手足無措,我們應當以什么標准來選擇,加和?乘積?比值?都不行吧,可以隨便舉反例。正解是,兩個權值g,s任選其一作為標准從小到大排序,比如選擇g就以g的大小排,再看s的大小,我們造一個棧,從底到頂s從小到大,每放一條邊調整棧中各邊的位置,做一遍kruskal,記錄答案,時間復雜度是O(nm)。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #define maxn 100010 7 #define ll long long 8 #define inf 1ll<<60 9 using namespace std; 10 int gmax,smax,n,m,G,S,fa[maxn],st[maxn],top,tot; 11 ll ans=inf; 12 struct Edge{ 13 int u,v,g,s; 14 }e[maxn]; 15 bool cmp(Edge x,Edge y) 16 { 17 return x.g<y.g; 18 } 19 int find(int x) 20 { 21 return x==fa[x]?x:fa[x]=find(fa[x]); 22 } 23 int main() 24 { 25 //freopen("road.in","r",stdin); 26 //freopen("road.out","w",stdout); 27 int u,v,g,s; 28 scanf("%d%d",&n,&m); 29 scanf("%d%d",&G,&S); 30 for(int i=1;i<=m;++i) scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].g,&e[i].s); 31 sort(e+1,e+m+1,cmp); 32 for(int i=1;i<=m;++i){ 33 int j=0; 34 for(j=1;j<=n;++j) fa[j]=j; 35 for(j=top;j>=1;--j) 36 if(e[st[j]].s>e[i].s) 37 st[j+1]=st[j]; 38 else break; 39 top++; 40 st[j+1]=i; 41 tot=0; 42 for(j=1;j<=top;++j) 43 { 44 int k1=find(e[st[j]].u),k2=find(e[st[j]].v); 45 if(k1!=k2){ 46 fa[k1]=k2; 47 st[++tot]=st[j]; 48 } 49 if(tot==n-1) break; 50 } 51 if(tot==n-1) ans=min(ans,1ll*e[i].g*G+1ll*e[st[n-1]].s*S); 52 top=tot; 53 } 54 if(ans==inf) printf("-1"); 55 else printf("%I64d",ans); 56 return 0; 57 }
————————————————懶得打分割線啊——————————————————
芒果君:考了這么多次,這場翻車最厲害,都倒數了QAQ 還是想太多