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 }