第一题:吃奶酪 它也有两个小剪枝 1.就是当搜到一个数,但是它已经超过了已知答案,就return。 2.就是提前把距离都预处理出来 Code: #includebits/stdc++.husing namespace std;int n;bool vis[1005];
第一题:吃奶酪
它也有两个小剪枝
1.就是当搜到一个数,但是它已经超过了已知答案,就return。
2.就是提前把距离都预处理出来
Code:
#include<bits/stdc++.h> using namespace std; int n; bool vis[1005]; double ans=10000000,x[1005],y[1005],len[1010][1010]; void dfs(int step,double l,int now){ if(l>ans) return;//剪枝1 if(step==n){ if(ans>l) ans=l; return; } for(int i=1;i<=n;i++){ if(!vis[i]) continue; vis[i]=0; dfs(step+1,l+len[now][i],i); vis[i]=1; } } int main(){ scanf("%d",&n); x[0]=0;y[0]=0; for(int i=1;i<=n;i++){ scanf("%lf%lf",&x[i],&y[i]); vis[i]=1; } for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ len[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));//剪枝2 } } dfs(0,0.0,0); printf("%.2lf",ans); }
第二题:健康的荷斯坦奶牛
这题有点复杂(至少我这么觉得)
虽然这是pj-,但我觉得这是tg-
我看这道题,想了半天递归的出口到底是什么。
然后我想就稍稍看了一眼题解 ,哦原来这道题要这么想!!好神奇!!
看代码吧,这道题我没想出来。(回头要再看看这道题)
Code:
#include<bits/stdc++.h> using namespace std; int G,V,v[3000],g[3000][3000],c[3000],wer[3000],answer=1000000; bool check(int x){ for(int i=1;i<=V;i++){ int ans=0; for(int j=1;j<=x;j++) ans+=g[c[j]][i]; //非常神奇 if(ans<v[i]) return false; } return true; }//这个check()函数是我第一次遇见。 void dfs(int t,int s){//t是第几种,s是一共用了几种 if(t>G){//结束的地方就是当要用的种类已经超过了所有的种类 if(check(s)){//check()函数,看看这个满足条件吗 if(s<answer){ answer=s; for(int i=1;i<=answer;i++){ wer[i]=c[i]; } } } return; } //这个大法师是我觉得最好的地方 c[s+1]=t;//如果选t dfs(t+1,s+1);//大法师 c[s+1]=0;//回溯 dfs(t+1,s);//大法师(没选t) } int main(){ scanf("%d",&V); for(int i=1;i<=V;i++) scanf("%d",&v[i]); scanf("%d",&G); for(int i=1;i<=G;i++){ for(int j=1;j<=V;j++){ scanf("%d",&g[i][j]); } } dfs(1,0); printf("%d",answer); for(int i=1;i<=answer;i++) printf(" %d",wer[i]); return 0; }
第三题:取数游戏
这道题的难点在于可能多个点把一个点设为不可选,所以当回溯时只可以--,
而不能让它直接=0。
#include<bits/stdc++.h> using namespace std; int a[100][100],step1,use[100][100],step2,ans,n,m,T; int a1[8]={1,1,1,0,0,-1,-1,-1},a2[8]={0,1,-1,1,-1,0,1,-1}; void dfs(int step1,int step2,int sum){ if(step2>m){ step1++; step2=1; } if(step1>n){ if(ans<sum) ans=sum; return; } if(use[step1][step2]==0){ //就是下面这句有可能有好几个数使得这个地方不可选 for(int i=0;i<=7;i++) use[step1+a1[i]][step2+a2[i]]++; dfs(step1,step2+2,sum+a[step1][step2]); for(int i=0;i<=7;i++) use[step1+a1[i]][step2+a2[i]]--; //上面这句,只能去-- (要不然就爆炸) } dfs(step1,step2+1,sum); } int main(){ scanf("%d",&T); while(T--){ ans=0; memset(use,0,sizeof(use)); memset(a,0,sizeof(a)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); } } dfs(1,1,0); printf("%d\n",ans); } return 0; }
第四题:油滴扩展
这道题的半径是难点,关键在于如何确定出来半径的大小。
#include<bits/stdc++.h> using namespace std; int n; double area,ans,d1,d2,d3,d4,xx1,yy1,xx2,yy2; double c[1000],x[1000],y[1000],use[1000],len[105][105]; void dfs(int shot,double sum){ if(shot>n){ if(sum>ans) ans=sum; return; } for(int k=1;k<=n;k++){ if(use[k]==0){ c[k]=min( min(abs(x[k]-d1),abs(x[k]-d2)) , min(abs(y[k]-d3),abs(y[k]-d4)) ); for(int j=1;j<=n;j++) if(use[j]) c[k]=min(c[k],len[k][j]-c[j]); if(c[k]<0) c[k]=0; use[k]=1; dfs(shot+1,sum+(M_PI*c[k]*c[k])); use[k]=0; } } } int main(){ scanf("%d%lf%lf%lf%lf",&n,&xx1,&yy1,&xx2,&yy2); for(int i=1;i<=n;i++){ scanf("%lf%lf",&x[i],&y[i]); x[i]+=1000; y[i]+=1000; } xx1+=1000,xx2+=1000,yy1+=1000,yy2+=1000; d1=min(xx1,xx2); d2=max(xx1,xx2); d3=min(yy1,yy2); d4=max(yy1,yy2); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) len[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); area=(abs(xx1-xx2)*abs(yy1-yy2)); dfs(1,0.0); printf("%d",int(area-ans+0.5)); return 0; }
第五题:小埋与扫雷
这道题给的链接,一共有两个!!!
都十分的重要,而我却一个都没看,所以???
尤其是八连通,我以为是大于等于8的连通块,实际是8个方向????
好吧,但是八连通怎么求还是值得看一眼的,看代码(不要以为我大法师,百凤山不分),我只是懒的写了。
#include<bits/stdc++.h> using namespace std; int ans,n,m,a[1005][1005],a1[8]={1,1,1,0,0,-1,-1,-1},a2[8]={1,0,-1,1,-1,1,0,-1}; void bfs(int p,int q){ if(p>=0&&p<=n&&q>=0&&q<=m&&a[p][q]==-1){ a[p][q]=2; for(int i=0;i<=7;i++) bfs(p+a1[i],q+a2[i]); } } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<=n+1;i++) for(int j=0;j<=m+1;j++) a[i][j]=2; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==1) continue; int jb=0; for(int k=0;k<=7;k++) if(a[i+a1[k]][j+a2[k]]==1) jb=1; if(jb==1) a[i][j]=2; if(jb==0) a[i][j]=-1; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==1||a[i][j]==-1) continue; int jb=0; for(int k=0;k<=7;k++) if(a[i+a1[k]][j+a2[k]]==0||a[i+a1[k]][j+a2[k]]==-1) jb=1; if(jb==0) ans++,a[i][j]=3; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]==-1) ans++,bfs(i,j); cout<<ans; return 0; }
第六题:海战
最开始看这道题的时候我还想,这不就是上面的题的求连通块放下来吗?
于是,真香
它需要判断连通块是否是一个矩形,其实这也十分简单,因为根据第一篇题解
不是矩形一定会这样的景象:
额,我废了好大的劲,可是为啥还是这么丑!!!
所以得出:如果4个格里有仨是有数的则不是矩形!
#include<bits/stdc++.h> using namespace std; int n,m,a[1005][1005],ans,rr,yy,ss; char ch; void dfs(int p,int q){ if(p>=0&&q>=0&&p<=n&&q<=m&&a[p][q]==1){ a[p][q]=2; dfs(p+1,q); dfs(p-1,q); dfs(p,q+1); dfs(p,q-1); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>ch;//这里有个天大的疑问,为啥我打scanf就会崩?! if(ch=='.') a[i][j]=0; else a[i][j]=1; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==1){ ans++; dfs(i,j); } } } //从这开始判断是不是矩形 for(int i=1;i<=n-1;i++){ for(int j=1;j<=m-1;j++){ int sum=a[i][j]+a[i+1][j]+a[i+1][j+1]+a[i][j+1]; if(sum==6){ cout<<"Bad placement."; return 0; } } } // 到这结束 printf("There are %d ships.",ans); return 0; }
第七题:‘SEARCH‘
额, 我不会搜索做,准确来说是不会剪枝,于是我一生气,就用模拟把它做出来了,可是我还是不会用搜索做,所以再等等,我问问大佬,应该就能出来。
模拟code 60ms,吸氧之后45ms:
#include<bits/stdc++.h> using namespace std; int n,m,r,a[55][55],cnt=1,way[1005],x,y; char ch,c[5],ac[55][55];; void wes(int p,int q,int temp){ for(int i=q-1;i>=1;i--){ if(a[p][i]==-1) break; a[p][i]=temp; } } void eas(int p,int q,int temp){ for(int i=q+1;i<=m;i++){ if(a[p][i]==-1) break; a[p][i]=temp; } } void sou(int p,int q,int temp){ for(int i=p+1;i<=n;i++){ if(a[i][q]==-1) break; a[i][q]=temp; } } void nor(int p,int q,int temp){ for(int i=p-1;i>=1;i--){ if(a[i][q]==-1) break; a[i][q]=temp; } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>ch; if(ch=='*') x=i,y=j,a[i][j]=1; if(ch=='X') a[i][j]=-1; } } scanf("%d",&r); for(int i=1;i<=r;i++){ cin>>c; if(c[0]=='N') way[++cnt]=4; if(c[0]=='S') way[++cnt]=1; if(c[0]=='E') way[++cnt]=2; if(c[0]=='W') way[++cnt]=3; } for(int k=2;k<=r+1;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==k-1){ if(way[k]==1) sou(i,j,k); if(way[k]==2) eas(i,j,k); if(way[k]==3) wes(i,j,k); if(way[k]==4) nor(i,j,k); } } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==-1) ac[i][j]='X'; if(a[i][j]<=r+1&&a[i][j]!=-1) ac[i][j]='.'; if(a[i][j]==r+1) ac[i][j]='*'; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<ac[i][j]; } cout<<endl; } return 0; }
TLE七个点(不会剪枝??)code(吸不吸氧一样):
#include<bits/stdc++.h> using namespace std; int n,m,r,a[55][55],cnt,way[1005],x,y; char ch,c[5],ac[55][55]; void dfs(int p,int q,int temp){ if(way[temp]==0){ return; } if(way[temp]==3){ for(int i=q-1;i>=1;i--){ if(a[p][i]==-1) break; if(a[p][i]<temp) a[p][i]=temp; dfs(p,i,temp+1); } } if(way[temp]==2){ for(int i=q+1;i<=m;i++){ if(a[p][i]==-1) break; if(a[p][i]<temp) a[p][i]=temp; dfs(p,i,temp+1); } } if(way[temp]==1){ for(int i=p+1;i<=n;i++){ if(a[i][q]==-1) break; if(a[i][q]<temp) a[i][q]=temp; dfs(i,q,temp+1); } } if(way[temp]==4){ for(int i=p-1;i>=1;i--){ if(a[i][q]==-1) break; if(a[i][q]<temp) a[i][q]=temp; dfs(i,q,temp+1); } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>ch; if(ch=='*') x=i,y=j; if(ch=='X') a[i][j]=-1; } } scanf("%d",&r); for(int i=1;i<=r;i++){ cin>>c; if(c[0]=='N') way[++cnt]=4; if(c[0]=='S') way[++cnt]=1; if(c[0]=='E') way[++cnt]=2; if(c[0]=='W') way[++cnt]=3; } dfs(x,y,1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==-1) ac[i][j]='X'; if(a[i][j]<=r&&a[i][j]!=-1) ac[i][j]='.'; if(a[i][j]==r) ac[i][j]='*'; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<ac[i][j]; } cout<<endl; } return 0; }