http://acm.pku.edu.cn/JudgeOnline/problem?id=3740
這道題目要求:選出一些行使得這些行構成矩陣的每一列都有且只有一個1。
1 #include<cstdio>
2 #include<string.h>
3 using namespace std;
4
5 int m,n,map[16][300];
6 bool used[300];
7 bool find;
8
9 bool match(){ //判斷所選取的行構成的矩陣是否符合情況
10 for(int i = 0;i < n;++i){
11 if(!used[i])return false;
12 }
13 return true;
14 }
15
16 bool check(int row){
17 for(int i = 0;i < n;++i){
18 if(used[i] && map[row][i])return false; //used[i]&&map[row][i]表示該列有選取的該列有不只一個1,返回false放棄這種情況。
19 }
20 for(int i = 0;i < n;++i){
21 if(map[row][i]){
22 used[i] = true;
23 }
24 }
25 return true;
26 }
27
28 void dfs(int start){
29 if(start>m || find)return;
30 if(match()){
31 printf("Yes, I found it\n");
32 find = true;
33 return;
34 }
35 for(int i = start;i < m && !find;++i){
36 if(check(i)){
37 dfs(i+1);
38 for(int j = 0;j < n;++j){
39 if(map[i][j])used[j] = false;
40 }
41 }
42 }
43 }
44
45 int main()
46 {
47 int i,j;
48 while(scanf("%d%d",&m,&n)!=EOF){
49 for(i = 0;i < m;++i){
50 for(j = 0;j < n;++j){
51 scanf("%d",&map[i][j]);
52 }
53 }
54 memset(used,false,sizeof(used));
55 find = false;
56 dfs(0);
57 if(!find)printf("It is impossible\n");
58 }
59 return 0;
60 }
61
http://acm.pku.edu.cn/JudgeOnline/problem?id=2528
這是一道經典的線段樹題目,另外加上離散化的方法。
離散化:由于題目中wall有10000000bytes long,直接線段樹無疑會MLE。所以要對其離散化,基本做法是:先對所有端點坐標進行排序,用相應序號代替端點坐標構造線段樹進行計算。這樣最大的序號也只是2*n。
在構造線段樹的節點結構體時,添加變量c。c=0時表示c線段沒有貼海報,或者貼了不止一張海報;c>0時表示貼了一張海報,并且c的值表示貼的是第幾張海報。
線段樹更新的基本原理就是,當我們貼海報i時,如果遇到某一線段區間能夠被當前海報完全覆蓋,那么我們更新到此區間即可,即讓它的變量c更新為海報i,記錄下i的值。如果不能被海報完全覆蓋,則只是這一線段區間的部分區間需要修改,則更改這一區間的子區間即可。
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<string.h>
5 #define MAX 20001
6
7 using namespace std;
8
9 int c,n,ls[MAX];
10 struct node{
11 int l,r;
12 int c;
13 }tree[MAX*4];
14 struct ln{
15 int li,num;//num表示第幾張海報
16 }line[MAX];
17 int set[MAX][2];
18 bool visit[MAX];
19 int ans;
20
21 bool cmp(struct ln a,struct ln b){
22 return a.li<b.li;
23 }
24
25 void Inittree(int pos,int ll,int rr){
26 tree[pos].l = ll;
27 tree[pos].r = rr;
28 tree[pos].c = 0;
29 if(ll!=rr){
30 int mid = (ll+rr)>>1;
31 Inittree(pos*2,ll,mid);
32 Inittree(pos*2+1,mid+1,rr);
33 }
34 }
35
36 void Insert(int pos,int ll,int rr,int color){
37 if(tree[pos].l == ll && tree[pos].r == rr){
38 tree[pos].c = color;
39 return;
40 }
41 if(tree[pos].c > 0 && tree[pos].c != color){
42 tree[pos*2].c = tree[pos].c;
43 tree[pos*2+1].c = tree[pos].c;
44 tree[pos].c = 0;
45 }
46 int mid = (tree[pos].l + tree[pos].r)>>1;
47 if(rr<=mid){
48 Insert(pos*2,ll,rr,color);
49 }
50 else if(ll>mid){
51 Insert(pos*2+1,ll,rr,color);
52 }
53 else{
54 Insert(pos*2,ll,mid,color);
55 Insert(pos*2+1,mid+1,rr,color);
56 }
57 }
58
59 void Search(int pos){
60 if(tree[pos].c!=0){
61 if(!visit[tree[pos].c]){//tree[pos].c
62 visit[tree[pos].c] = true;
63 ans++;
64 }
65 return ;
66 }
67 Search(2*pos);
68 Search(2*pos+1);
69 }
70
71 int main()
72 {
73 int i;
74 while(scanf("%d",&c)!=EOF){
75 while(c--){
76 scanf("%d",&n);
77 for(i = 0;i < n;++i){//離散化
78 scanf("%d%d",&set[i][0],&set[i][1]);
79 line[2*i].li = set[i][0];
80 line[2*i].num = -(i+1);//用負數表示 線段起點
81 line[2*i+1].li = set[i][1];
82 line[2*i+1].num = i+1;
83 }
84 sort(line,line+2*n,cmp);
85 int temp = line[0].li,tp = 1;
86 for(i = 0;i < 2*n;++i){
87 if(line[i].li != temp){
88 tp++;
89 temp = line[i].li;
90 }
91 if(line[i].num < 0){
92 set[-line[i].num-1][0] = tp;
93 }
94 else{
95 set[line[i].num-1][1] = tp;
96 }
97 }//離散化
98
99 Inittree(1,1,tp);
100 for(i = 0;i < n;++i){
101 Insert(1,set[i][0],set[i][1],i+1);
102 }
103 memset(visit,0,sizeof(visit));
104 ans = 0;
105 Search(1);
106 printf("%d\n",ans);
107 }
108 }
109 return 0;
110 }
111
http://acm.nankai.edu.cn/p1007.html,
http://acm.nankai.edu.cn/p1249.html這是兩個關于分解素數的問題,一個是分解為素數之和,一個是分解為素數之積。自己寫的總TLE,于是參考了別人的代碼,感覺方法果然巧妙。對于素數之和是找到素數規律了。
nkoj 1007
#include<stdio.h>
#include<stdlib.h>
int n;
int main()
{
scanf("%d",&n);
if(n%3){
switch(n%3){
case 1:printf("2 2 ");n-=4;break;
case 2:printf("2 ");n-=2;break;
}
}
while(n){
printf("3 ");
n-=3;
}
system("pause");
return 0;
}
code
nkoj 1249
#include<stdio.h>
#include<math.h>
int n,a;
int main()
{
scanf("%d",&n);
while(n--){
scanf("%d",&a);
int i,flag = 0;
int b=a;
for(i = 2;i <= b/2;i++){
if(a%i==0 && flag==0){
flag = 1;
a/=i;
printf("%d",i);
}
while(a%i==0){
a/=i;
printf("*%d",i);
}
}
if(flag == 0)printf("%d",a);
printf("\n");
}
return 0;
}
http://poj.grids.cn/problem?id=1664
從這道題目我認識到遞歸思想的強大。
#include<stdio.h>
int t;
int pro(int m,int n){
if(m == 0||n == 1)return 1;
if(m < n)return pro(m,m);
return pro(m,n-1)+pro(m-n,n);
}
int main()
{
scanf("%d",&t);
int m,n;
while(t--){
scanf("%d%d",&m,&n);
printf("%d\n",pro(m,n));
}
return 0;
}
http://acm.nankai.edu.cn/p1019.html
大數相加,利用數組存儲,再加上適當處理。
1 #include<stdio.h>
2 #include<string.h>
3 char a[101],b[101];
4 int c[101];
5 int main()
6 {
7 while(scanf("%s%s",a,b) != EOF){
8 memset(c,0,sizeof(c));
9 int i,j,k;
10 for(i = strlen(a)-1,j = strlen(b)-1,k = 0;i>=0 || j>=0;k++){
11 c[k] = (i>=0?(a[i--]-'0'):0) + (j>=0?(b[j--]-'0'):0);
12 }
13 for(i = 0;i < k;++i){
14 if(c[i] > 9){
15 c[i+1] += c[i]/10;
16 c[i] = c[i]%10;
17 }
18 }
19 while(!c[k]){
20 k--;
21 }
22 for(i = k;i>=0;--i){
23 printf("%d",c[i]);
24 }
25 printf("\n");
26 }
27 return 0;
28 }
http://acm.nankai.edu.cn/p1002.html
乍看不難,其實也不難。就是不能用遞歸來做。巧妙地利用變量l來處理,體會!
1 #include<stdio.h>
2 #include<stdlib.h>
3 long n;
4 int main()
5 {
6 while(scanf("%d",&n) != EOF){
7 long l = 1;
8 while(l>0){
9 if(n >= 50025002){
10 n -= 5;
11 l--;
12 }
13 else{
14 n += 2005;
15 l++;
16 }
17 }
18 printf("%d\n",n);
19 }
20 system("pause");
21 return 0;
22 }
23
http://poj.grids.cn/problem?id=2692
利用枚舉,從'A'到'L'。判斷條件是:如果是'even',則天平兩邊無假幣;如果是'up',若為light,則假幣一定在天平右側,若為heavy,則假幣一定在天平左側;如果是'down',情況相反。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 char left[3][7],right[3][7],result[3][5];
5 bool isLight(char c);
6 bool isheavy(char c);
7 int main()
8 {
9 int n;
10 while(scanf("%d",&n) != EOF){
11 while(n--){
12 for(int i = 0;i < 3;i++)
13 scanf("%s%s%s",left[i],right[i],result[i]);
14 char x;
15 for(x = 'A';x <= 'L';x++){
16 if(isLight(x)){
17 printf("%c is the counterfeit coin and it is light.\n",x);
18 break;
19 }
20 if(isheavy(x)){
21 printf("%c is the counterfeit coin and it is heavy.\n",x);
22 break;
23 }
24 }
25 }
26 }
27 system("pause");
28 return 0;
29 }
30
31 bool isLight(char c)
32 {
33 for(int i = 0;i < 3;i++){
34 if(!strcmp(result[i],"even"))
35 if(strchr(left[i],c) != NULL || strchr(right[i],c) != NULL)return false;
36 if(!strcmp(result[i],"up"))
37 if(strchr(right[i],c) == NULL)return false;
38 if(!strcmp(result[i],"down"))
39 if(strchr(left[i],c) == NULL)return false;
40 }
41 return true;
42 }
43
44 bool isheavy(char c)
45 {
46 for(int i = 0;i < 3;i++){
47 if(!strcmp(result[i],"even"))
48 if(strchr(left[i],c) != NULL || strchr(right[i],c) != NULL)return false;
49 if(!strcmp(result[i],"up"))
50 if(strchr(left[i],c) == NULL)return false;
51 if(!strcmp(result[i],"down"))
52 if(strchr(right[i],c) == NULL)return false;
53 }
54 return true;
55 }
56
http://poj.grids.cn/problem?id=2977
題目是要求三個生理周期高峰出現在同一天的時間,即三個數的最小公倍數。
1 #include<stdio.h>
2 int p,e,j,d;
3 int main()
4 {
5 int k = 1;
6 int i;
7 while(scanf("%d%d%d%d",&p,&e,&j,&d) != EOF && p != -1){
8 for(i = d+1;i < 21252;++i)
9 if((i-p)%23 == 0)break;
10 for(;i < 21252;i+=23)
11 if((i-e)%28 == 0)break;
12 for(;i < 21252;i+=23*28)
13 if((i-j)%33 == 0)break;
14 printf("Case %d: the next triple peak occurs in %d days.\n",k++,i-d);
15 }
16 return 0;
17 }
18
http://acm.pku.edu.cn/JudgeOnline/problem?id=1068
這道題目是一道模擬題。P-sequence表示第i個‘)’之前有幾個‘(’,W-sequence表示第i個‘()’包含幾對‘()’,要求對應P的W。題目中沒有要輸出S,故‘(’‘)’可以分別用0,1來代替。根據P可以輕易知道‘)’的位置:location = p[i] + i。用value記錄w[i]的值,用flag記錄括號是否成對。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 int t,n;
5 int s[41],p[21],w[21];
6 int main()
7 {
8 scanf("%d",&t);
9 while(t--){
10 scanf("%d",&n);
11 int temp,flag,value;
12 memset(s,0,sizeof(s));
13 for(int i = 0;i < n;++i){
14 scanf("%d",&p[i]);
15 temp = p[i] + i;
16 s[temp] = 1;
17 for(int k = temp-1,value = 1,flag = 0;k >= 0;--k){
18 if(s[k] == 0 && flag == 0){
19 w[i] = value;
20 break;
21 }
22 else if(s[k] == 1){
23 value++;
24 flag++;
25 }
26 else if(s[k] == 0)flag--;
27 }
28 }
29 for(int i = 0;i < n;++i)printf("%d ",w[i]);
30 printf("\n");
31 }
32 system("pause");
33 return 0;
34 }
35
code
http://acm.pku.edu.cn/JudgeOnline/problem?id=1008
這是一道關于歷法轉換的問題。從這道題我得到2點收獲:一、題目中月份或者日期是用字符串來表示的,這時利用二位數組可以輕松實現從字符串到數字的轉換;二、Tzolkin中的日期和月數是相互獨立的,可分別取余。
另外,我覺得很重要的一點就是,一定要清楚題目是從0,還是從1開始數的,并且在取余時候關于這方面一定要保持頭腦清醒。很容易出錯。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 int n;
5 char haabmonth[19][10] = {"pop","no","zip","zotz","tzec","xul","yoxkin","mol","chen","yax","zac","ceh","mac","kankin","muan","pax","koyab","cumhu","uayet"};
6 char tzolkinday[20][10] = {"imix","ik","akbal","kan","chicchan","cimi","manik","lamat","muluk","ok","chuen","eb","ben","ix","mem","cib","caban","eznab","canac","ahau"};
7 int day;
8 char month[10];
9 int year;
10 int main()
11 {
12 scanf("%d",&n);
13 printf("%d\n",n);
14 for(int i = 0;i < n;++i){
15 scanf("%d. %s %d",&day,month,&year);
16 int days;
17 for(int k = 0;k < 19;++k){
18 if(!strcmp(haabmonth[k],month)){
19 days = year * 365 + k * 20 + day;
20 break;
21 }
22 }
23 int m = days % 260;
24 printf("%d %s %d\n",m%13+1,tzolkinday[m%20],days/260);
25 }
26 system("pause");
27 return 0;
28 }
29
code