USACO 3.1 分析

來源:互聯網
上載者:User

題目一: Agri-Net

演算法:MST

方法1:kruskal

要用到並查集的方法

int getfa(int x) {return fa[x] == x ? x : fa[x] = getfa(fa[x]);}

1.把邊從小到大排序;

2.初始化:每個點自成一棵樹,形成森林;

3.按邊權值從小到大枚舉,找到不在一棵樹中的兩個點,將這兩棵樹合并,累計權值;

小細節:記錄下需要計算的代表元的結果;

#include <stdio.h><br />#include <string.h><br />const<br />int max = 101*100+1;<br />int u[max], v[max], w[max], fa[101], r[max];<br />void swap(int &a, int &b) {<br />int temp = a;<br />a = b;<br />b = temp;<br />}<br />int getfa(int x) {return fa[x] == x ? x : fa[x] = getfa(fa[x]);}<br />int main(){<br />freopen("agrinet.in", "r", stdin);<br />freopen("agrinet.out", "w", stdout);<br />int n;<br />scanf("%d", &n);<br />int tot = 0, d;<br />for (int i = 0; i < n; i++)<br />for (int j = 0; j < n; j++) {<br />scanf("%d", &d);<br />if (i < j) {<br />tot++;<br />v[tot] = i;<br />u[tot] = j;<br />w[tot] = d;<br />}<br />}<br />for (int i = 1; i < tot; i++)<br />for (int j = i+1; j <= tot; j++)<br />if (w[i] > w[j]) {<br />swap(v[i], v[j]);<br />swap(w[i], w[j]);<br />swap(u[i], u[j]);<br />}</p><p>//for (int i = 1; i <= tot; i++) printf("%d %d %d/n", u[i], v[i], w[i]);<br />for (int i = 0; i < n; i++) fa[i] = i;<br />int cost = 0, rest = n-1;<br />for (int i = 1; i <= tot && rest > 0; i++) {<br />int x = getfa(u[i]), y = getfa(v[i]);<br />if (x != y) {<br />cost += w[i];<br />fa[x] = y;<br />rest--;<br />}<br />}<br />printf("%d/n", cost);<br />return 0;<br />}<br />

 

方法二:PRIM

#include <string.h><br />#include <assert.h><br />const<br />int max = 101;<br />int map[max][max], vis[max], d[max];<br />int main(){<br />freopen("agrinet.in", "r", stdin);<br />freopen("agrinet.out", "w", stdout);</p><p>int n;<br />scanf("%d", &n);<br />for (int i = 0; i < n; i++)<br />for (int j = 0; j < n; j++)<br />scanf("%d", &map[i][j]);</p><p>/*intialize*/<br />int cost = 0;<br />for (int i = 0; i < n; i++) {<br />d[i] = (1 << 31)-1;<br />vis[i] = 0;<br />}<br />vis[0] = 1;<br />d[0] = 0;<br />for (int i = 1; i < n; i++) d[i] = map[0][i];</p><p>/*PRIM body*/<br />for (int i = 1; i < n; i++) {<br />int min = (1 << 31)-1, p = -1;<br />for (int j = 0; j < n; j++)//get the minimal unvisited point<br />if (!vis[j] && d[j] < min) {<br />min = d[j];<br />p = j;<br />}<br />cost += d[p];<br />vis[p] = 1;<br />for (int j = 0; j < n; j++)//update the info<br />if (!vis[j] && map[p][j] < d[j])<br />d[j] = map[p][j];<br />}<br />printf("%d/n", cost);<br />return 0;<br />}

 

題目二:Score inflation

演算法:無限背包

 

題目三:Humble Numbers

題目描述:給定若干質因子,求出由這些質因子所能構成的所有整數中的第K大數是多少

演算法:動態規劃

1.最初的想法是用D[I]表示以第i個質數結尾當前以產生的最大質數,但是錯的,會漏掉一些數;

2.後來看了MAIGO的代碼,自己琢磨了兩天明白了他的方法,用D[I]表示第i個質數當前用來產生新數的數在產生的數串中的位置,這樣肯定不會漏;

#include <stdio.h><br />#include <string.h><br />const<br />int maxn = 101;<br />int n[maxn], m[maxn], h[100001];<br />int main(){<br />freopen("humble.in", "r", stdin);<br />freopen("humble.out", "w", stdout);<br />int N, K;<br />scanf("%d %d", &N, &K);<br />for (int i = 0; i < N; i++)<br />scanf("%d", &n[i]);<br />int last = 1;<br />memset(h,0,sizeof(h));<br />memset(m,0,sizeof(m));<br />h[0] = 1;<br />for (int i =1; i <= K; i++) {<br />int min =(1 << 31)-1;<br />for (int j = 0; j < N; j++)<br />if (h[m[j]] * n[j] > h[i-1] && h[m[j]] * n[j] < min)<br />min = n[j] * h[m[j]];<br />h[i] = min;<br />for (int j = 0; j < N; j++)<br />if (h[m[j]] * n[j] == min) m[j]++;<br />}<br />printf("%d/n", h[K]);<br />return 0;<br />}

 

題目四:Shaping Regions

題目大意:依次給定N個有色矩形,覆蓋,求最後的圖形中各種可見顏色的面積

演算法:搜尋

1.最開始的想法是從後往前枚舉,然後與後面的圖形進行切割,但是具體怎麼切割不清楚;

2.看了MAIGO的代碼,體會了一下,明白了;

3.與後面的切割時,先去處理X兩邊多出來的部分,重點是要更新X,然後在處理Y兩邊

 #include <string.h><br />#include <stdio.h><br />const<br />int maxn = 1001;<br />int n, x1[maxn], y1[maxn], x2[maxn], y2[maxn], color[maxn], area[maxn];<br />int now;<br />void calc(int X1, int Y1, int X2, int Y2, int z) {<br />while (z <= n && (X1 >= x2[z] || X2 <= x1[z] || Y1 >= y2[z] || Y2 <= y1[z]) ) z++; // find the nearest rec which has common area<br />if (z > n) {//the final existing area which isn't covered by any rec put after it<br />area[now] += (X2 - X1) * (Y2 - Y1);<br />return;<br />}<br />if (X1 < x1[z]) {<br />calc(X1, Y1, x1[z], Y2, z+1);<br />X1 = x1[z];//cut the processed area<br />}<br />if (X2 > x2[z]) {<br />calc(x2[z], Y1, X2, Y2, z+1);<br />X2 = x2[z];//cut the processed area<br />}<br />if (Y1 < y1[z]) calc(X1, Y1, X2, y1[z], z+1);//as the coordinate X has been processed, Y is the factor only being dealt with<br />if (Y2 > y2[z]) calc(X1, y2[z], X2, Y2, z+1);<br />}<br />int main(){<br />freopen("rect1.in", "r", stdin);<br />freopen("rect1.out", "w", stdout);<br />memset(x1,0,sizeof(x1));<br />memset(x2,0,sizeof(x2));<br />memset(y1,0,sizeof(y1));<br />memset(y2,0,sizeof(y2));<br />memset(area,0,sizeof(area));<br />scanf("%d %d %d/n", &x2[0], &y2[0], &n);<br />color[0] = 1;// the empty color is numbered 1<br />for (int i = 1; i <= n; i++) scanf("%d %d %d %d %d/n", &x1[i], &y1[i], &x2[i], &y2[i], &color[i]);<br />int maxcolor = 0;<br />for (int i = n; i >= 0; i--) {<br />now = color[i];//the color now is processed<br />calc(x1[i], y1[i], x2[i], y2[i], i+1);<br />if (now > maxcolor) maxcolor = now;<br />}<br />for (int i = 1; i <= maxcolor; i++)<br />if (area[i] > 0) printf("%d %d/n", i, area[i]);<br />return 0;<br />}<br />

 

題目五:Contact

題目大意:給定01串,求出長度為A-B之間各個01串的數量最多的前K組

演算法:枚舉+位處理

1.基本思路很清晰,一次枚舉位,然後對新形成的串進行分類,但關鍵是怎麼儲存這個串以及怎麼更新這個串;

資料結構:

01便想到位元運算,把2進位轉化為10進位,長度為L的01串前加個1便可區分不同長度的相同數值的01串;

更新:

   1.先去掉開頭的1;  2.增加當前位的值;  3.把開頭的數值用|運算強制轉成1

對應的位元運算分別為
s[j] &= (1 << L)-1

s[j] = (s[j] << 1) + ss[i] -'0';

s[j] |= (1 << j);

2.接下來的問題是輸出格式的控制,建議先把所有有的串排個序,在分個類,出現相同數目的01串有幾個,然後輸出,容易控制;

 #include <stdio.h><br />#include <string.h><br />const<br />int maxlen = 12, maxn = 1 << maxlen+1;<br />int s[maxlen+1], d[maxlen+1], t[maxn], num[maxn], tt[52];<br />char ss[82];<br />void swap(int &a, int &b) {<br />int temp = a;<br />a = b;<br />b = temp;<br />}<br />void print(int num) {<br />int len = 0;<br />while (num > 0) {<br />d[++len] = num % 2;<br />num /= 2;<br />}<br />for (int i = len-1; i >= 1; i--)<br />printf("%d", d[i]);<br />}<br />int main(){<br />freopen("contact.in", "r", stdin);<br />freopen("contact.out", "w", stdout);<br />int A, B, N;<br />scanf("%d %d %d/n", &A, &B, &N);<br />//infinitial the bit opration to 10..00<br />for (int i = A; i <= B; i++) s[i] = 1 << i;<br />int len = 0;<br />while (scanf("%s", ss) == 1)<br />for (int i = 0; i < strlen(ss); i++) {<br />len++;<br />for (int j = A; j <= B; j++) {<br />s[j] &= (1 << j)-1;//delete the head<br />s[j] = (s[j] << 1) + ss[i] -'0';// insert the new digit<br />s[j] |= (1 << j);//plus the head<br />if (len >= j) t[s[j]]++;//new string is built<br />}<br />}<br />//sort array t in discreased order<br />int min = 1 << A, max = (1 << (B+1))-1;<br />for (int i = min; i <= max; i++) num[i] = i;//num as the second key in increased order<br />for (int i = 1, k = min;i <= max; i++, k++)<br />for (int j = k+1; j <= max; j++)<br />if (t[j] > t[k] || t[j] == t[k] && num[j] < num[k]) {<br />swap(t[k], t[j]);<br />swap(num[k], num[j]);<br />}<br />//output the string, first get tt[i] means the number of group<br />int n = 0;<br />for (int k = min; k <= max; k++) {<br />if (t[k] == 0 || n > N) break;<br />if (k == 1 || t[k] != t[k-1]) tt[++n]++; else tt[n]++;<br />}<br />if (n < N) N = n;<br />n = min-1;//means the position<br />for (int i = 1; i <= N; i++) {<br />printf("%d/n", t[++n]);<br />print(num[n]);<br />for (int j = 2; j <= tt[i]; j++) {if (j % 6 != 1) printf(" ");print(num[++n]);if (j % 6 == 0 && j != tt[i]) printf("/n");}<br />printf("/n");<br />}<br />return 0;<br />}<br />

 

題目六:Stamps

題目大意:有若干種基礎面值的郵票,每種數量無限,求最多用K張郵票不能拼出的最小數是多少

演算法:BFS

1.在基礎面值確定的條件下,每一張面值所需最少郵票數是這個面值的固有屬性;
2.一開始想用DP,但方程找不出來,後來想到用BFS的向後拓展的功能可以實現,基於1,每個點最多被加入一次隊列,空間用4B-INT型需要15M,所以改用4B-INT+2B-SHORT需11.5M,實際用了14M

#include <stdio.h><br />#include <string.h><br />const<br />int maxvalue = 2000000, MAX = 1 << 15-1;<br />short need[maxvalue+1], w[51];<br />int q[maxvalue+1];<br />int main(){<br />freopen("stamps.in", "r", stdin);<br />freopen("stamps.out", "w", stdout);<br />int n, k;<br />//printf("%d/n", sizeof(short));<br />scanf("%d %d/n", &k, &n);<br />for (int i = 0; i < n; i++) scanf("%d", &w[i]);<br />for (int i = 0; i <= maxvalue; i++) need[i] = MAX;<br />need[0] = 0;q[0] = 0;<br />int head = 0, tail = 0;<br />while (head <= tail) {<br />if (need[q[head]] < k)<br />for (int i = 0; i < n; i++)<br />if (need[q[head]]+1 < need[q[head]+w[i]]) {<br />tail++;<br />q[tail] = q[head]+w[i];<br />need[q[tail]] = need[q[head]]+1;<br />}<br />head++;<br />}<br />int max = 0;<br />while (need[++max] != MAX) {};<br />printf("%d/n", max-1);<br />return 0;<br />}<br />

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.