很久沒有在線編程了,實力大大減弱。為了保持算法與編程的技能,繼續找一下在線比賽來復習復習。只為找感覺,不求排名與晉級。
一 傳話游戲
http://programming2013.cstnet.cn/qualification/problem/1
題目簡意:一句由若干個單詞組成的話,經過N個人傳承。每個人在聽取前一個人的口述時,都會把某些單詞聽成另外的單詞。求最終被流傳下來的句子。
解: 不能再水了,就是簡單的字符串替換。不想用c寫字符串的東西,於是用了java的HashMap<String,String>,還是第一次用java提交。注意類名一定要是Main

1 2 import java.util.HashMap; 3 import java.util.Scanner; 4 5 public class Main{ 6 7 8 public static int T, N, M; 9 10 public static int count = 1; 11 public static HashMap<String,String> rule; 12 13 public static String orignal, result; 14 public static Scanner cin = new Scanner(System.in); 15 16 17 public static void main(String[] args){ 18 19 T = cin.nextInt(); 20 21 while(T-- > 0) 22 { 23 N = cin.nextInt(); 24 M = cin.nextInt(); 25 result = ""; 26 27 rule = new HashMap<String,String>(); 28 for(int i = 0; i < M; i++) 29 { 30 String ori = cin.next().toString(); 31 String swp = cin.next().toString(); 32 rule.put(ori, swp); 33 } 34 35 orignal = cin.next().toString(); 36 orignal += cin.nextLine().toString(); 37 38 39 String[] sentence = orignal.split(" "); 40 41 42 while(N > 1) 43 { 44 for(int i = 0; i < sentence.length; i++) 45 if (rule.containsKey(sentence[i])) 46 sentence[i] = rule.get(sentence[i]); 47 N--; 48 } 49 50 String result = ""; 51 for (int i=0;i<sentence.length;i++) 52 result += " "+sentence[i]; 53 54 System.out.println("Case #" + count++ + ":" + result); 55 56 } 57 } 58 59 }
二 長方形
http://programming2013.cstnet.cn/qualification/problem/2
題目概要:在 N 條水平線與 M 條豎直線構成的網格中,放 K 枚石子,每個石子都只能放在網格的交叉點上。問在最優的擺放方式下,最多能找到多少四邊平行於坐標軸的長方形,它的四個角上都恰好放着一枚石子。
輸入:第一行,給出一個整數T,為數據組數。接下來依次給出每組測試數據。
每組數據為三個用空格隔開的整數 N,M,K。
1 ≤ T ≤ 100
0 ≤ K ≤ N * M
小數據:0 < N, M ≤ 30
大數據:0 < N, M ≤ 30000
解:這是一道排列組合的問題。假設我們已經知道從K個石子中取X*Y個組成一個大的飽滿的矩形,它上面每一行的石子數目相同,剩余L個石子,0<L<X。則此時的矩形總數為:在飽滿的大矩形中,共有C(x,2)*C(y,2)個小矩形,剩下的和L有關的矩形數是X*C(L,2) 。兩者的和即為所求。
如何選取X和Y呢?應該可以理論證明的,但是我懶得去推,因為N,M<= 30000, 可以枚舉每一個X的值。(似乎真的太懶了。。。)

1 #include<stdio.h> 2 #include<math.h> 3 4 unsigned long long solve() 5 { 6 int i,j,k; 7 int t,n,m; 8 unsigned long long mx = 0; 9 int x,y,l; 10 unsigned long long cur; 11 12 scanf("%d%d%d",&n,&m,&k); 13 if (n>m) 14 { 15 t=n;n=m;m=t; 16 } 17 for (i=2;i<=n;i++) 18 { 19 x=i; 20 y = k / i; 21 l = k % i; 22 if (y>m || y==m && l>0) 23 continue; 24 cur = x*y*(x-1)*(y-1)/4 + y * (l-1)*l/2; 25 if (cur>mx) 26 mx = cur; 27 } 28 return mx; 29 } 30 31 int main() 32 { 33 int T,i; 34 scanf("%d",&T); 35 for (i=1;i<=T;i++) 36 printf("Case #%d: %llu\n",i,solve()); 37 return 0; 38 }
這個平台和杭電的又有所不同,輸出不能用%I64d ,而要用%llu 來輸出 unsigned long long。
三 樹上的三角形
有一棵樹,樹上有只毛毛蟲。它在這棵樹上生活了很久,對它的構造了如指掌。所以它在樹上從來都是走最短路,不會繞路。它還還特別喜歡三角形,所以當它在樹上爬來爬去的時候總會在想,如果把剛才爬過的那幾根樹枝/樹干鋸下來,能不能從中選三根出來拼成一個三角形呢?
1 ≤ T ≤ 5
小數據:1 ≤ N ≤ 100, 1 ≤ M ≤ 100, 1 ≤ len ≤ 10000
大數據:1 ≤ N ≤ 100000, 1 ≤ M ≤ 100000, 1 ≤ len ≤ 1000000000
解:一看就讓人想到用最近公共祖先和並查集。但是我現在不想花太多精力去實現它,於是就決定水一下小數據。
首先要說的是,小數據的范圍是1000,而不是100!害我檢查了N次,太無恥了。
拿到樹的結構以后,任取一個節點,遍歷一遍樹,為了得到每個節點的深度(假設根節點的深度為0)和它的父節點。
然后對每一對節點s和t,沿着他們的父節點一層一層上移,直到遇到第一個公共祖先。(利用每個節點的深度)。並把這條路徑上的邊壓入一個數組中。
接着對保存有邊的數組進行排序。遍歷一次排序好的數組,如果存在相鄰的三條邊能構成三角形,那么就yes,否則就no。

1 #include<stdio.h> 2 #define size 900 3 int N,M; 4 int c[size][size]; 5 int dep[size]; 6 int father[size]; 7 int visited[size]; 8 int edge[size]; 9 int cnt; 10 11 void Broadcast(int s, int d ) 12 { 13 int i; 14 15 visited[s] = 1; 16 dep[s] = d; 17 int fa,fb; 18 19 20 for (i=1;i<=N;i++) 21 if (visited[i]==0 && c[s][i]>0) 22 { 23 father[i] = s; 24 Broadcast(i,d+1 ); 25 } 26 } 27 28 void sort(int s[] , int cnt) 29 { 30 int t; 31 int i,j; 32 for (i=0;i<cnt;i++) 33 for (j=i+1;j<=cnt;j++) 34 if (s[i]>s[j]) 35 { 36 t = s[i]; 37 s[i] = s[j]; 38 s[j] = t; 39 } 40 } 41 42 void solve() 43 { 44 45 int i,j,k; 46 int s,t,w; 47 int ok ; 48 int fa,fb; 49 scanf("%d",&N); 50 51 52 for (i=1;i<=N;i++) 53 { 54 visited[i] = 0; 55 for (j=1;j<=N;j++) 56 { 57 c[i][j] = 0; 58 c[j][i] = 0; 59 } 60 } 61 62 for (i=1;i<N;i++) 63 { 64 scanf("%d %d %d",&s,&t,&w); 65 c[s][t] = w; 66 c[t][s] = w; 67 } 68 69 scanf("%d",&M); 70 father[1] = 1; 71 72 Broadcast(1,0 ); 73 for (k=0;k<M;k++) 74 { 75 scanf("%d %d",&s,&t); 76 // printf("No\n"); 77 // continue; 78 fa = s; 79 fb = t; 80 cnt = 0; 81 82 while (fa != fb) 83 { 84 if (dep[fa]>dep[fb]) 85 { 86 fa = father[fa]; 87 } 88 else fb = father[fb]; 89 } 90 91 while (s != fa) 92 { 93 edge[cnt++] = c[s][father[s]]; 94 s = father[s]; 95 } 96 while (t != fa) 97 { 98 edge[cnt++] = c[t][father[t]]; 99 t = father[t]; 100 } 101 102 //qsort(edge,0,cnt-1); 103 sort(edge,cnt-1); 104 ok = 0; 105 for (i=0;i<cnt-2;i++) 106 { 107 if (edge[i]+edge[i+1] > edge[i+2]) 108 { 109 ok = 1; 110 break; 111 } 112 } 113 if (ok==1) 114 printf("Yes\n"); 115 else printf("No\n"); 116 } 117 } 118 119 int main() 120 { 121 int T; 122 int i; 123 scanf("%d",&T); 124 for (i=1;i<=T;i++) 125 { 126 printf("Case #%d:\n",i); 127 solve(); 128 } 129 return 0; 130 }