題目一:The Longest Prefix
題目大意:給出一組可以去匹配的字串,求在給定的字串中最長可以匹配出的首碼有多長?
演算法1:DP
效率:O(200,000*200*10) (實際遠遠不到)
對於每個位置,去枚舉每個字串,在除去這個串之後的前面的串可以匹配的情況下判斷對應的位時候可以匹配,只要有一個可以匹配該位就可以匹配。如果連續遇到不可匹配的數目大於最大可以匹配的長度的時候,就可以退出了。
小經驗:用scanf("%c", c)讀字元不能跳過斷行符號符和空格
#include <stdio.h><br />#include <string.h><br />#include <string><br />#include <iostream><br />using namespace std;<br />const<br />int maxlen = 200000+2;<br />bool h[maxlen];<br />char ch[maxlen];<br />char s[11];<br />char pri[201][11];<br />bool check(int nowpos, int i) {<br />if (strlen(pri[i]) > nowpos || !h[nowpos-strlen(pri[i])]) return false;<br />for (int k = 0, j = nowpos-strlen(pri[i])+1; k < strlen(pri[i]); k++, j++)<br />if (pri[i][k] != ch[j]) return false;<br />return true;<br />}<br />void print(int tot_pri) {<br />for (int i = 0; i < tot_pri; i++)<br />printf("%s/n", pri[i]);<br />}<br />int main(){<br />freopen("prefix.in", "r", stdin);<br />freopen("prefix.out", "w", stdout);<br />int tot_pri = 0, maxs = 0;//maxs record the longest length of the pri<br />while (true) {<br />scanf("%s", s);<br />if (s[0] == '.') break;<br />memcpy(pri[tot_pri], s, sizeof(s));<br />tot_pri++;<br />if (strlen(s) > maxs) maxs = strlen(s);<br />}<br />//print(tot_pri);<br />int len = 0, maxmiss = 0, max = 0;//maxmiss record the longest length which can't compare<br />char c;<br />memset(h,0,sizeof(h));<br />h[0] = 1;<br />c = getchar();<br />while (scanf("%c", &c) == 1) {//read success<br />if (c == '/n') continue;<br /> len++;<br />ch[len] = c;<br />bool flag = false;<br />for (int i = 0; i < tot_pri && !flag; i++) flag = check(len, i);<br />if (!flag) maxmiss++;<br />else { maxmiss = 0;max = len;}<br />if (maxmiss > maxs) break;<br />h[len] = flag;<br />}<br />printf("%d/n", max);<br />return 0;<br />}<br />
測試時間:
Test 1: TEST OK [0.000 secs, 3276 KB]
Test 2: TEST OK [0.000 secs, 3276 KB]
Test 3: TEST OK [0.011 secs, 3276 KB]
Test 4: TEST OK [0.022 secs, 3276 KB]
Test 5: TEST OK [0.022 secs, 3276 KB]
Test 6: TEST OK [0.054 secs, 3276 KB]
演算法2:Trie(單詞尋找樹)(這種演算法好像當時一下子就寫出來了,但到現在才知道它的名字)
效率:O(200,000)
題目二:Cow Pedigrees
題目大意:求N個結點高度為K的樹的種數
演算法:DP
效率:O(NK)
s[i][j] = s[left][h]*s[right][j-1] + s[left][j-1]*s[right][h] + s[left][j-1]*s[right][j-1] 1<=h<=j-2,1<=left, right <i and left + right + 1 = i
最佳化:滿足這種條件的樹的節點數一定為奇數;最大高度不會超過(N+1)/2;
#include <stdio.h><br />#include <string.h><br />int s[100][100];<br />int main(){<br />freopen("nocows.in", "r", stdin);<br />freopen("nocows.out", "w", stdout);<br />int N, K;<br />scanf("%d%d", &N, &K);<br />memset(s,0,sizeof(s));//s[i][j] i*2+1 nodes of height j<br />s[0][1] = 1;<br />if ((N & 1) == 0) printf("0/n"); else {<br />N = (N-1) >> 1;<br />for (int i = 1; i <= N; i++) {<br />int maxh = i+1;<br />if (K < maxh) maxh = K;<br />for (int h = 1; h <= maxh; h++)<br />for (int j = 0; j < i; j++) {<br /> for (int hh = 1; hh < h-1; hh++)<br />s[i][h] = (s[i][h] + s[j][hh]*s[i-j-1][h-1] + s[i-j-1][hh]*s[j][h-1]) % 9901;<br />s[i][h] = (s[i][h] + s[j][h-1]*s[i-j-1][h-1]) % 9901;<br />}<br />}<br />printf("%d/n", s[N][K]);<br />}<br />return 0;<br />}<br />
題目三:Zero Sum
演算法:DFS
注意:算的時候要從左向右算,從右向左算稍麻煩;
#include <stdio.h><br />#include <string.h><br />int num[10], calc[10];<br />int n;<br />void dfs(int depth) {<br />if (depth == n) {<br />memset(num,0,sizeof(num));<br />int len = 0;<br />num[0] = 1;<br />for (int i = 1; i < n; i++)<br />if (calc[i] == 0) num[len] = num[len]*10+(i+1);<br />else num[++len] = (i+1);<br />len =0;<br />for (int i = 1; i < n; i++)<br />if (calc[i] == 1) {<br />num[len+1] += num[len];<br />len++;<br />} else<br />if (calc[i] == 2){<br />num[len+1] = num[len] - num[len+1];<br />len++;<br />}<br />if (num[len] == 0) {<br />printf("1");<br />for (int i = 1; i < n; i++) {<br />if (calc[i] == 0) printf(" "); else<br />if (calc[i] == 1) printf("+"); else<br /> printf("-");<br />printf("%d", i+1);<br />}<br />printf("/n");<br />}<br />return;<br />}<br />for (int i = 0; i <= 2; i++) {<br />calc[depth] = i;<br />dfs(depth+1);<br />calc[depth] = 0;<br />}<br />}<br />int main(){<br />freopen("zerosum.in", "r", stdin);<br />freopen("zerosum.out", "w", stdout);<br />scanf("%d", &n);<br />memset(calc,0,sizeof(calc));<br />dfs(1);<br />return 0;<br />}<br />
題目四:Money Systems
演算法:DP 背包
小知識:INT64在DEV-C++的g++編譯器中printf("%I64d",n),而在GNU中要寫成printf("%lld",n)
#include <stdio.h><br />#include <string.h><br />long long s[10001];<br />int main(){<br />freopen("money.in", "r", stdin);<br />freopen("money.out", "w", stdout);<br />int V, N;<br />scanf("%d%d", &V, &N);<br />memset(s,0,sizeof(s));<br />s[0] = 1;<br />int unit;<br />for (int i = 0; i < V; i++) {<br />scanf("%d", &unit);<br />for (int v = unit; v <=N; v++) s[v] += s[v-unit];<br />}<br />printf("%lld/n", s[N]);<br />return 0;<br />}
題目五:Controlling Company
演算法:DFS/BFS
關鍵是要理解題目中的規則
(1)不解釋(2)不解釋(3)你的控制的公司稱為子公司,則子公司的子公司仍然是你的公司,也受你的管轄
這道題實質是圖論的題目,可以用鄰接表來存貯,哪種搜尋隨便了。第一條規則在搜尋時意味著你先把自己作為本體去拓展
#include <stdio.h><br />#include <string.h><br />const<br />int maxn = 101, max = maxn*maxn/2;<br />int own[maxn];<br />bool vis[maxn];<br />int first[maxn], next[max], v[max], w[max];<br />void dfs(int x) {<br />if (vis[x]) return;<br />vis[x] = true;<br />for (int now = first[x]; now >= 0; now = next[now]) {<br />own[v[now]] += w[now];<br />if (own[v[now]] > 50)<br />dfs(v[now]);<br />}<br />}<br />int main(){<br />freopen("concom.in", "r", stdin);<br />freopen("concom.out", "w", stdout);<br />int n;<br />scanf("%d", &n);<br />int m = 0, u;<br />for (int i = 1; i <= maxn-1; i++) first[i] = -1;<br />for (int i = 0; i < n; i++) {<br />scanf("%d%d%d", &u, &v[i], &w[i]);<br />next[i] = first[u];<br />first[u] = i;<br />if (u > m) m = u;<br />if (v[i] > m) m = v[i];<br />}<br />for (int i = 1; i <= m; i++){<br />memset(own, 0, sizeof(own));<br />memset(vis, 0, sizeof(vis));<br />dfs(i);<br />for (int j = 1; j <= m; j++)<br />if (own[j] > 50 && i != j)<br />printf("%d %d/n", i, j);<br />}<br />return 0;<br />}<br />