冲刺省选习题集

1.火柴棒等式

   单击此处看题目

考察算法:数学分析+枚举

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 const int match[10]={6,2,5,5,4,5,6,3,7,6};
 6 
 7 int n;
 8 
 9 int merge(int x){
10     int sum=0;
11     if(x==0)return 6;
12     while(x){
13         sum+=match[x%10];
14         x/=10;
15     }
16     return sum;
17 }
18 
19 int main(){
20     freopen("matches.in","r",stdin);
21     freopen("matches.out","w",stdout);
22     scanf("%d",&n);
23     int a,b,c,res=0;
24     n-=4;
25     for(a=0;a<=1000;a++)
26         for(b=0;b<=1000;b++)
27         {
28             c=a+b;
29             if(n==(merge(a)+merge(b)+merge(c)))
30                 res++;
31         }
32     printf("%d",res);
33     return 0;
34 }

2.作业调度方案

     单击此处看题目

考察算法:语文分析+模拟+离散化

具体做法:将工件的工序离散到机器的时间轴,然后寻找插入即可

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int MaxN=21;
 8 
 9 int n,m,cost[MaxN][MaxN];
10 int machen[MaxN][MaxN]; 
11 int d[MaxN*MaxN];
12 int num[MaxN];
13 bool ok[MaxN][MaxN*MaxN];
14 int f[MaxN][MaxN];
15 
16 void readfile(){
17     freopen("jsp.in","r",stdin);
18     freopen("jsp.out","w",stdout);
19     scanf("%d%d",&m,&n);//m个机器,n个工件数,m道工序
20     int i,j,x;
21     for(i=1;i<=m*n;i++)scanf("%d",&d[i]);
22     for(i=1;i<=n;i++)
23         for(j=1;j<=m;j++)
24           scanf("%d",&machen[i][j]);//第i个工件第j道工序应放入的机器号machen[i][j] 
25     for(i=1;i<=n;i++)
26       for(j=1;j<=m;j++)
27           scanf("%d",&cost[i][j]);//第i件工件第j道工序花费的时间 
28 }
29 
30 void work(){
31     int i,j,k,p,sss,ans=0;
32     bool flag=false;
33     memset(ok,false,sizeof(ok));
34     for(i=1;i<=m*n;i++)
35     {
36         k=machen[d[i]][++num[d[i]]];//按照顺序第i件工件所应该放的机器号 
37         p=f[d[i]][num[d[i]]-1];
38         while(1){
39             flag=false;
40             sss=p;
41             for(j=0;j<cost[d[i]][num[d[i]]];j++)
42               if(ok[k][p++]==true){
43                   flag=true;
44                   break;
45               }
46             if(flag==false)break;
47         }
48         for(j=0;j<cost[d[i]][num[d[i]]];j++)
49           ok[k][sss+j]=true;
50         f[d[i]][num[d[i]]]=p;
51         ans=max(ans,p);
52     }
53     cout<<ans;
54 }
55 
56 int main(){
57     readfile();
58     work();
59     return 0;
60 }

3.引水入城

  单击此处看题目

考察算法:广度优先搜索染色(FLOOD_FILL)+贪心

具体做法:首先利用BFS求出p数组和g数组(作用程序段中会给出),然后我们扫描p数组如果len=0则证明没有城市可以流入,累计下来输出0,否则用贪心的思想,累计每个蓄水厂可以流到的线段的左端点和右端点,然后求下一个,以此类推,时间复杂度O(NM)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int MaxN=501;
 8 
 9 struct element{
10     int L,R;//表示该点能流入的左端点和右端点 
11     element(){L=1<<30;R=0;}
12 }g[MaxN];
13 
14 struct xOy{
15     int X,Y;
16 };
17 
18 int n,m,height[MaxN][MaxN];
19 int p[MaxN][MaxN],len[MaxN];//流入第n行第i列的城市的编号 
20 bool vis[MaxN][MaxN];
21 
22 void bfs(int x,int y){
23     queue<xOy> q;
24     int headx,heady;
25     memset(vis,false,sizeof(vis));
26     q.push((struct xOy){x,y});
27     vis[x][y]=true;
28     while(!q.empty()){
29         headx=q.front().X;
30         heady=q.front().Y;
31         q.pop();
32         if(headx==n){
33           p[heady][++len[heady]]=y;
34           g[y].L=min(g[y].L,heady);
35           g[y].R=max(g[y].R,heady);
36         }
37         if(headx-1>0 && vis[headx-1][heady]==false && height[headx][heady]>height[headx-1][heady])
38         {
39           q.push((struct xOy){headx-1,heady});
40           vis[headx-1][heady]=true;
41         }
42         if(headx+1<=n && vis[headx+1][heady]==false && height[headx][heady]>height[headx+1][heady])
43         {
44           q.push((struct xOy){headx+1,heady});
45           vis[headx+1][heady]=true;
46         }
47         if(heady-1>0 && vis[headx][heady-1]==false && height[headx][heady]>height[headx][heady-1])
48         {
49           q.push((struct xOy){headx,heady-1});
50           vis[headx][heady-1]=true;
51         }
52         if(heady+1<=m && vis[headx][heady+1]==false && height[headx][heady]>height[headx][heady+1])
53         {
54           q.push((struct xOy){headx,heady+1});
55           vis[headx][heady+1]=true;
56         }
57     }
58 }
59 
60 int main(){
61     freopen("flow.in","r",stdin);
62     freopen("flow.out","w",stdout);
63     scanf("%d%d",&n,&m);
64     int i,j,tot=0,MAX=0;
65     for(i=1;i<=n;i++)
66       for(j=1;j<=m;j++)
67         scanf("%d",&height[i][j]);
68     for(i=1;i<=m;i++)bfs(1,i);
69     for(i=1;i<=m;i++)
70       if(len[i]==0)tot++;
71     if(tot>0){
72         printf("0\n%d",tot);
73         return 0;
74     }
75     for(i=1;i<=m;)
76     {
77         MAX=0;
78         for(j=1;j<=len[i];j++)//贪心的寻找一个最优位置 
79           if(g[p[i][j]].R>MAX)
80               MAX=g[p[i][j]].R;
81         i=MAX+1;
82         tot++;
83     }
84     printf("1\n%d",tot);
85     return 0;
86 }

4.国王游戏

  单击此处看题目

  考察算法:贪心+高精度(高除单+高乘单)

  具体操作:按左右手乘积从小到大排序

 1 //挖掘机技术哪家强?中国山东找蓝翔 
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <cstring>
 7 #include <algorithm>
 8 #include <string>
 9 using namespace std;
10 
11 const int MaxN=1000001;
12 const int Max_Size=1000001;
13 const int mod=10000;//万进制
14 
15 struct person{
16     int Left,Right;
17     friend bool operator< (person c,person b){
18         return c.Left*c.Right<b.Left*b.Right;//greedy
19     }
20 }a[MaxN];
21 
22 int n;
23 int Now[Max_Size],l1;
24 int hav[Max_Size],l;//当前大臣所能获得的钱
25 int best[Max_Size],lb;//最多的钱
26 
27 void init(){
28     freopen("game.in","r",stdin);
29     freopen("game.out","w",stdout);
30     scanf("%d",&n);
31     int i;
32     scanf("%d%d",&a[0].Left,&a[0].Right);//国王 
33     for(i=1;i<=n;i++)scanf("%d%d",&a[i].Left,&a[i].Right);
34 }
35 
36 int comp(int a[],int b[]){
37     int i;
38     if(l>lb)return 1;
39     else if(l<lb)return 0;
40     for(i=1;i<=lb;i++)
41       if(a[i]>b[i])return 1;
42       else if(a[i]<b[i])return 0;
43     return 0;
44 }
45 
46 void change(){
47     int i;
48     lb=l;
49     for(i=1;i<=l;i++)best[i]=hav[i];
50 }
51 
52 void greedy(){
53     sort(a+1,a+n+1);//按照左右手乘积从小到大排序 
54     int i,j,tmp=0,k=0;
55     Now[l1=1]=1;//初始化当前值 
56     for(i=1;i<=n;i++){
57         for(j=1;j<=l1;j++){
58             tmp=Now[j]*a[i-1].Left+k;
59             Now[j]=tmp%mod;
60             k=tmp/mod;
61         }
62         while(k>0){
63             Now[++l1]=k%mod;
64             k/=mod;
65         }
66         tmp=l=0;
67         for(j=l1;j>=1;j--){
68             hav[++l]=(tmp*mod+Now[j])/a[i].Right;
69             tmp=(tmp*mod+Now[j])%a[i].Right;
70         }
71         if(comp(hav,best)==1)change();
72     } 
73     int front=1;
74     while(best[front]==0)front++;
75     printf("%d",best[front]);
76     for(i=front+1;i<=lb;i++)printf("%4.4d",best[i]);      
77 }
78 
79 int main(){
80     init();
81     greedy();
82     return 0;
83 }

5.2^k进制数

6.聪明的质检员

  单击此处看题目

  考察算法:分治(二分答案)+线型DP+二次函数分析

  具体操作:二分W,然后利用二次函数得出W和Y成反比例,所以用函数来计算Y,如果过大则增大W,反之同理

  时间复杂度O(NMlogWmax)

  优化:通过DP的前缀和手段,O(1)时间查找该区间满足条件的价值总和和个数

  代码有注释

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 
 7 const int MaxN=200001;
 8 
 9 struct segment{
10     int l,r;
11 }a[MaxN];
12 
13 int n,m;
14 long long s,Y;
15 int w[MaxN],v[MaxN];
16 
17 void init(){
18     freopen("qp.in","r",stdin);
19     freopen("qp.out","w",stdout);
20     cin>>n>>m>>s;
21     int i;
22     for(i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);
23     for(i=1;i<=m;i++)scanf("%d%d",&a[i].l,&a[i].r);
24 }
25 
26 int f[MaxN];//前i个矿石质量大于等于W的个数 
27 long long g[MaxN];//前i个质量大于等于W的矿石总价值
28  
29 void check(int W){
30     int i;
31     Y=0;
32     memset(f,0,sizeof(f));
33     memset(g,0,sizeof(g));
34     for(i=1;i<=n;i++)//初始化g和f数组 
35     {
36         f[i]=f[i-1];
37         g[i]=g[i-1];
38         if(w[i]>=W){
39             f[i]=f[i-1]+1;
40             g[i]=g[i-1]+v[i];
41         }
42     }
43     for(i=1;i<=m;i++)
44       Y+=(f[a[i].r]-f[a[i].l-1])*(g[a[i].r]-g[a[i].l-1]);
45 }
46 
47 void solve(){
48     int low=1,high=0,mid;
49     int i;
50     long long ans=1LL<<60;
51     for(i=1;i<=n;i++)//以最大质量为最大值 
52       if(w[i]>high)
53         high=w[i];
54     while(low<=high){
55         mid=(low+high)>>1;//二分答案
56         check(mid);
57         if(abs(Y-s)<ans)ans=abs(Y-s);
58         if(Y>s)low=mid+1;
59         else high=mid-1;
60     }
61     cout<<ans;
62 }
63 
64 int main(){
65     init();
66     solve();
67     return 0;
68 } 

7.斐波那契数列

8.Hankson的趣味题

9.同余方程

  单击此处看题目

  考察算法:拓展欧几里得+数学变换

  题目要求解ax=1 (mod b)

  显然有ax=by+1 (y (- Z)

  那么转变得ax-by=1

  此时我们可以假想为求2元一次不定方程的最小解

  使用拓展欧几里得来解决

  但是注意,这里不是ax+by=1,所以x需要消除符号,即多次求模即可

  x=(x%b+b)%b

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 int a,b;
 6 /* ax=1(mod b)
 7    ax=by+1
 8    ax-by=1
 9    ax+(-by)=1
10 */
11 
12 int exgcd(int a,int b,int &x,int &y){
13     if(b==0){
14         x=1;
15         y=0;
16         return a;
17     }
18     else{
19         int ans=exgcd(b,a%b,x,y);
20         int t=x;
21         x=y;
22         y=t-a/b*y;
23         return ans;
24     }
25 }
26 
27 int main(){
28     cin>>a>>b;
29     int x,y;
30     x=y=0;
31     exgcd(a,b,x,y);
32     x=(x%b+b)%b;
33     cout<<x;
34     return 0;
35 }

10.栈

 单击此处看题目

 考察算法:记忆化搜索或者Catalan数推导公式

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 int n;
 6 long long f=1;
 7 
 8 int main(){
 9     cin>>n;
10     for(int i=2;i<=n;i++)f=f*(2*(2*i-1))/(i+1);
11     cout<<f;
12     return 0;
13 }

11.八数码难题

  单机此处看题目

 考察算法:

    二B青年:暴力宽搜

    普通青年:双向广搜

    文艺青年:启发式搜索(也就是我!(*^__^*) 嘻嘻……)

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cmath>
  5 #include <cstring>
  6 using namespace std;
  7 
  8 const int MaxM=100000008;
  9 const int OK[9][2]={{2,2},{1,1},{1,2},{1,3},{2,3},{3,3},{3,2},{3,1},{2,1}};
 10 
 11 bool apper[MaxM];//Hash
 12 
 13 struct segment{
 14     int f,g,h;//估价函数
 15     short a[10][10];
 16     int empty_x,empty_y;
 17     segment(){f=g=h=0;}
 18     friend bool operator< (segment a,segment b){
 19         return a.f>b.f;
 20     } 
 21 }stat;
 22 
 23 priority_queue<segment> q;
 24 
 25 void init(){
 26     int i,j,x=0;
 27     for(i=1;i<=3;i++)
 28       for(j=1;j<=3;j++){
 29           scanf("%1d",&stat.a[i][j]);
 30           x=x*10+stat.a[i][j];
 31           if(stat.a[i][j]==0)stat.empty_x=i,stat.empty_y=j;
 32       }
 33     q.push(stat);
 34     memset(apper,false,sizeof(apper));
 35     apper[x/10]=true;
 36 }
 37 
 38 int get_corn(segment b){
 39     int x=0,i,j;
 40     for(i=1;i<=3;i++)
 41       for(j=1;j<=3;j++)
 42         x=x*10+b.a[i][j];
 43     return x;
 44 }
 45 
 46 int Man_Ha_Dun(int x1,int y1,int x2,int y2){
 47     return abs(x1-x2)+abs(y1-y2);
 48 }
 49 
 50 int get_future(segment b){
 51     int i,j,total=0;
 52     for(i=1;i<=3;i++)
 53       for(j=1;j<=3;j++)
 54         total+=Man_Ha_Dun(i,j,OK[b.a[i][j]][0],OK[b.a[i][j]][1]);//求出不在位将牌到初始位置的路径总和作为启发函数的一部分 
 55     return total;
 56 }
 57 
 58 void heuristic_search(){
 59     int i,j,t;
 60     segment head;
 61     while(!q.empty()){
 62         head=q.top();
 63         q.pop();
 64         if(get_corn(head)==123804765){cout<<head.g;return;}
 65         if(head.empty_x-1>=1){
 66             swap(head.a[head.empty_x-1][head.empty_y],head.a[head.empty_x][head.empty_y]);
 67             if(apper[get_corn(head)/10]==false){
 68                 apper[get_corn(head)/10]=true;
 69                 head.g++;
 70                 t=head.h;
 71                 head.empty_x--;
 72                 head.h=get_future(head);
 73                 head.f=head.g+head.h;//更新启发函数  
 74                 q.push(head);
 75                 head.empty_x++;
 76                 head.g--;//还原状态 
 77                 head.h=t;
 78                 head.f=head.g+head.h;
 79             }
 80             swap(head.a[head.empty_x-1][head.empty_y],head.a[head.empty_x][head.empty_y]);
 81         }
 82         if(head.empty_y-1>=1){
 83             swap(head.a[head.empty_x][head.empty_y-1],head.a[head.empty_x][head.empty_y]);
 84             if(apper[get_corn(head)/10]==false){
 85                 apper[get_corn(head)/10]=true;
 86                 head.g++;
 87                 t=head.h;
 88                 head.empty_y--;
 89                 head.h=get_future(head);
 90                 head.f=head.g+head.h;//更新启发函数  
 91                 q.push(head);
 92                 head.empty_y++;
 93                 head.g--;//还原状态 
 94                 head.h=t;
 95                 head.f=head.g+head.h;
 96             }
 97             swap(head.a[head.empty_x][head.empty_y-1],head.a[head.empty_x][head.empty_y]);
 98         }
 99         if(head.empty_x+1<=3){
100             swap(head.a[head.empty_x+1][head.empty_y],head.a[head.empty_x][head.empty_y]);
101             if(apper[get_corn(head)/10]==false){
102                 apper[get_corn(head)/10]=true;
103                 head.g++;
104                 t=head.h;
105                 head.h=get_future(head);
106                 head.empty_x++;
107                 head.f=head.g+head.h;//更新启发函数  
108                 q.push(head);
109                 head.empty_x--;
110                 head.g--;//还原状态 
111                 head.h=t;
112                 head.f=head.g+head.h;
113             }
114             swap(head.a[head.empty_x+1][head.empty_y],head.a[head.empty_x][head.empty_y]);
115         }
116         if(head.empty_y+1<=3){
117             swap(head.a[head.empty_x][head.empty_y+1],head.a[head.empty_x][head.empty_y]);
118             if(apper[get_corn(head)/10]==false){
119                 apper[get_corn(head)/10]=true;
120                 head.g++;
121                 t=head.h;
122                 head.h=get_future(head);
123                 head.empty_y++;
124                 head.f=head.g+head.h;//更新启发函数  
125                 q.push(head);
126                 head.empty_y--;
127                 head.g--;//还原状态 
128                 head.h=t;
129                 head.f=head.g+head.h;
130             }
131             swap(head.a[head.empty_x][head.empty_y+1],head.a[head.empty_x][head.empty_y]);
132         }
133     }
134 }
135 
136 int main(){
137     init();
138     heuristic_search();
139     return 0;
140 }

 ============================动态规划专题===============================

【线型DP】

1.乘积最大

2.最长公共子序列

3.最长不下降子序列

4.编辑距离

【背包DP】

1.乌龟棋

2.采药

3.机器分配

【区间DP】

1.石子合并

2.能量项链

【棋盘DP】

1.免费馅饼

2.传纸条

   单击此处看题目

  考察算法:双向棋盘DP

  设f(x1,y1,x2,y2)表示纸条1在(x1,y1),纸条2在(x2,y2)这个位置所能获得的总的最大值

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int n,m,a[51][51];
 5 int f[51][51][51][51];
 6 
 7 int main(){
 8     cin>>n>>m;
 9     int i,j,i1,j1,i2,j2;
10     for(i=1;i<=n;i++)
11       for(j=1;j<=m;j++)
12         cin>>a[i][j];
13     for(i1=1;i1<=n;i1++)
14       for(j1=1;j1<=m;j1++)
15         for(i2=1;i2<=n;i2++)
16               for(j2=1;j2<=m;j2++)
17                 if((i1!=i2 && j1!=j2) || (i1==i2 && j1==j2 && i1==n && j1==m)){
18                     f[i1][j1][i2][j2]=max(max(f[i1-1][j1][i2-1][j2],f[i1-1][j1][i2][j2-1]),max(f[i1][j1-1][i2-1][j2],f[i1][j1-1][i2][j2-1]));
19                     f[i1][j1][i2][j2]+=a[i1][j1]+a[i2][j2];
20                 }
21     cout<<f[n][m][n][m];
22     return 0;
23 }

 

posted @ 2015-02-09 21:00  MedalPluS  阅读(243)  评论(0编辑  收藏  举报