USACO 2.1 分析

來源:互聯網
上載者:User

第一題 The Castle

演算法:求連通分量的個數

題目給出的形式很好,沒有以強的形式給出,而是以1,2,4,8來對應二進位給出,還要打牆~~~

 

痛點1:怎樣判斷有沒有牆?

位元運算可以發揮作用了!

 

痛點2:怎樣敲牆?

由於題目中有西是最優的,其次是南,所以枚舉的順序有關係;其次,要先敲N,再去敲E,可以寫兩個FOR,也可以把它過程化;

小細節:敲的時候兩邊要屬於不同的連通分量啊!

 

這道題目比以前的代碼大大縮減,只有60++,很高興!
#include <stdio.h><br />#include <string.h><br />const<br />int max = 50 + 3, dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};<br />int num[max][max], map[max][max], s[max*max], qx[max*max], qy[max*max];<br />int n, m;</p><p>int newMaxArea = 0, newx, newy, newk;<br />void calc(int j, int k) {<br />for (int i = n; i > 0; i--) // wall second farthest to the south<br />if ( (map[i][j] & (1 << k)) ) {<br /> int nowx = i+dx[k], nowy = j+dy[k];<br /> if (num[nowx][nowy] != num[i][j] && s[num[i][j]] + s[ num[i+dx[k]][j+dy[k]] ] > newMaxArea) {<br /> newx = i; newy = j;<br /> newMaxArea = s[num[i][j]] + s[ num[nowx][nowy] ];<br /> newk = k;<br /> }<br />}<br />}</p><p>int main() {<br />freopen("castle.in", "r", stdin);<br />freopen("castle.out", "w", stdout);<br />scanf("%d%d", &m, &n);<br />for (int i = 1; i <= n; i++)<br />for (int j = 1; j <= m; j++)<br />scanf("%d", &map[i][j]);</p><p>/*number the adjusted-parts and get the separate area*/<br />int number = 0, maxarea = 0;<br />s[0] = - 1 << 20; // let the area outside the border be the minimal area<br />memset(num, 0, sizeof(num));<br />for (int i = 1; i <= n; i++)<br />for (int j = 1; j <= m; j++)<br />if (!num[i][j]) {<br />number++;<br />num[i][j] = number;<br />qx[0] = i; qy[0] = j;<br />int first = 0, last = 0;<br />while (first <= last) {<br />for (int k = 0; k < 4; k++)<br />if ( !(map[qx[first]][qy[first]] & (1 << k)) ) {<br />int nowx = qx[first] + dx[k], nowy = qy[first] + dy[k];<br />if (!num[nowx][nowy]) {<br />qx[++last] = nowx;<br />qy[last] = nowy;<br />num[nowx][nowy] = number;<br />}<br />}<br />first++;<br />}<br />s[number] = last + 1;<br />if (s[number] > maxarea) maxarea = s[number];<br />}</p><p>/*get the removed wall*/<br />for (int j = 1; j <= m; j++) {// wall first farthest to the west<br />calc(j,1);<br />calc(j,2);<br />}</p><p>/*print the answer*/<br />printf("%d/n%d/n%d/n%d %d %c/n", number, maxarea, newMaxArea, newx, newy, newk == 1 ? 'N':'E');<br />return 0;<br />}<br />

小問題:maxarea >?= s[number] 在USACO上編譯不能通過?

 

第二題:Ordered Fractions

題目意思很明白,第一反映排序,而且NLOGN排序可以過,於是沒想其他方法,就上了。

看了Analysis後,Russ有一種遞迴直接產生解的方法,很厲害啊。

We notice that we can start with 0/1 and 1/1 as our ``endpoints'' and recursively generate the middle points by adding numerators and denominators. </p><p>0/1 1/1<br /> 1/2<br /> 1/3 2/3<br /> 1/4 2/5 3/5 3/4<br /> 1/5 2/7 3/8 3/7 4/7 5/8 5/7 4/5</p><p>Each fraction is created from the one up to its right and the one up to its left. This idea lends itself easily to a recursion that we cut off when we go too deep.<br />#include <stdio.h><br />#include <stdlib.h><br />#include <string.h><br />#include <assert.h></p><p>int n;<br />FILE *fout;</p><p>/* print the fractions of denominator <= n between n1/d1 and n2/d2 */<br />void<br />genfrac(int n1, int d1, int n2, int d2)<br />{<br />if(d1+d2 > n)/* cut off recursion */<br />return;</p><p>genfrac(n1,d1, n1+n2,d1+d2);<br />fprintf(fout, "%d/%d/n", n1+n2, d1+d2);<br />genfrac(n1+n2,d1+d2, n2,d2);<br />}</p><p>void<br />main(void)<br />{<br />FILE *fin;</p><p>fin = fopen("frac1.in", "r");<br />fout = fopen("frac1.out", "w");<br />assert(fin != NULL && fout != NULL);</p><p>fscanf(fin, "%d", &n);</p><p>fprintf(fout, "0/1/n");<br />genfrac(0,1, 1,1);<br />fprintf(fout, "1/1/n");<br />}</p><p>

 

 第三題:Sorting A Three-Valued Sequence

這道題很水,先兩個盡量交換,剩下的只能三個交換了,由於最終的排列是給定的,所以只需O(N)的時間

#include <stdio.h><br />#include <string.h><br />const<br />int maxn = 1000;<br />int num[4] = {0,0,0,0}, s[4][4];<br />int a[maxn];<br />void calc(int start, int end, int sym) {<br />for (int i = start; i <= end; i++)<br />s[sym][a[i]]++;<br />}<br />int min(int a, int b) {<br />if (a > b) return b; else return a;<br />}<br />int main() {<br />freopen("sort3.in", "r", stdin);<br />freopen("sort3.out", "w", stdout);<br />int n;<br />scanf("%d", &n);<br />for (int i = 1; i <= n; i++) {<br />scanf("%d", &a[i]);<br />num[a[i]]++;<br />}<br />memset(s,0,sizeof(0));<br />for (int i = 1; i <= 3; i++) {<br />num[i] = num[i]+num[i-1];<br />calc(num[i-1]+1,num[i],i);<br />}<br />int tot = 0;<br />for (int i = 1; i <= 3; i++)<br />for (int j = 1; j <= 3; j++)<br />if (i != j) {<br />int Min = min(s[i][j], s[j][i]);<br />tot += Min;<br />s[i][j] -= Min;<br />s[j][i] -= Min;<br />}<br />tot += (s[1][2]+s[1][3]) << 1;<br />printf("%d/n", tot);<br />return 0;<br />}<br />

 

第四題:Healthy Holstein

最多也只有15種飼料,0/1枚舉也就32768種,能承受,如果用二進位來構造方案統計的效率比較低,所以還是用DFS了來構造選擇方案比較划算

小技巧:記錄選擇的方案不需要一個數組,只需一個位元來記錄,方便,快速,給力!

#include <stdio.h><br />#include <string.h><br />const<br />int maxneed = 25+3, maxtype = 15+3;<br />int minchoose = 1 << 20, path, choose = 0, minpath, n, type;<br />int map[maxtype][maxneed], get[maxneed], need[maxneed];<br />bool check() {<br />for (int i = 0; i < n; i++)<br />if (get[i] < need[i]) return false;<br />return true;<br />}<br />void dfs(int now) {<br />if (minchoose < choose) return; //小小的剪枝<br />if (now == type) {<br />if (choose < minchoose && check()) {<br />minpath = path;<br />minchoose = choose;<br />}<br />return;<br />}<br />//choose<br />path = (path << 1)+1;<br />choose++;<br />for (int i = 0; i < n; i++) get[i] += map[now][i];<br />dfs(now+1);<br />for (int i = 0; i < n; i++) get[i] -= map[now][i];<br />choose--;<br />path = path >> 1;<br />//not choose<br />path = path << 1;<br />dfs(now+1);<br />path = path >> 1;<br />}<br />int main() {<br />freopen("holstein.in", "r", stdin);<br />freopen("holstein.out", "w", stdout);<br />scanf("%d", &n);<br />for (int i = 0; i < n; i++)<br />scanf("%d", &need[i]);<br />scanf("%d", &type);<br />for (int i = 0; i < type; i++)<br />for (int j = 0; j < n; j++)<br />scanf("%d", &map[i][j]);<br />path = 0;<br />memset(get,0,sizeof(get));<br />dfs(0);<br />printf("%d ", minchoose);<br />for (int i = type-1; i >= 0; i--)<br />if (minpath & (1 << i))<br />printf("%d%c", type-i, --minchoose?' ':'/n');<br />return 0;<br />}<br />

 

第五題:Hamming Codes

要用到位元運算來擷取第N位位元的操作;另外可以先預先處理出所有數對之間的距離,我想資料本身就不太大,不預先處理了,還浪費空間,時間還是挺可以的

#include <stdio.h><br />#include <string.h><br />const<br />int max = 256, maxN = 64+3;<br />short int dis[max][max];<br />int N, B, D;<br />int path[maxN];<br />bool check(int a, int b) {<br />int dif = 0;<br />for (int i = 0; i < B; i++)<br />if ((a & (1 << i)) != (b & (1 << i))) dif++;<br />if (dif >= D) return true; else return false;<br />}<br />int dfs(int now) {<br />if (now == N) {<br />for (int i = 0; i < N; i++)<br />printf("%d%c", path[i], i % 10 == 9 || i == N-1?'/n':' ');<br />return 1;<br />}<br />int temp = path[now-1];<br />while (true) {<br />temp++;<br />bool flag = true;<br />for (int i = 0; i < now; i++)<br />if (!check(path[i], temp)) {<br />flag = false;<br />break;<br />}<br />if (flag) {<br />path[now] = temp;<br />if (dfs(now+1)) return 1;<br />}<br />if (temp > (1 << B)-1) {<br />printf("Impossible");<br />return 1;<br />}<br />}<br />}<br />int main() {<br />freopen("hamming.in", "r", stdin);<br />freopen("hamming.out", "w", stdout);<br />scanf("%d%d%d", &N, &B, &D);<br />memset(path,0,sizeof(path));<br />path[0] = 0;<br />path[1] = (1 << D) - 1;<br />dfs(2);<br />return 0;<br />}<br />

 

 

好久閑著了,今天下午+晚上間歇得把2.1寫完了,還是有收穫的,明天晚上就要動身去學校了,短暫的寒假結束了,準備迎接新一輪的挑戰吧!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.