刷题时,刷到了阮一峰的博客,看了看感觉是个比较有想法的人,有兴趣可以百度一下
先记录下今天的学习吧
给一张图,从1点出发,要求是一次走完后,再求出这次中从1点到达各个点的总时间,其中每个点都有deadlinetime
先是对这个图跑一遍floyd,让每个点都预处理一下,然后进行深搜,深搜的时候要注意剪枝
最优性剪枝和可行性剪枝
#include<bits/stdc++.h> using namespace std; int str[35][35]; int n,ans,dd[35]; int vis[35]; int inf=0x3f3f3f3f; void floyd() { for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) str[i][j]=min(str[i][j],str[i][k]+str[k][j]); } } } void dfs(int s,int time,int total,int cnt)//time为到达某个点的时间//total为总时间,cnt剩余点数 { if(cnt==0) { ans=min(ans,total); return; } if (total+cnt*time >= ans) //后面的点的time肯定是越来越大的,假设都为time,最优性剪枝 return; for(int i=2;i<=n;i++)//这个循环和下面要分开写 ,这个是判断当前点s 的可行性剪枝 if(!vis[i]&&time+str[s][i]>dd[i]) return;//s到其他点有超时的,那么再从这点出发后不管怎样都可定超时 for(int i=2;i<=n;i++) { if(!vis[i]) { vis[i]=1; dfs(i, time+str[s][i] , total+time+str[s][i], cnt-1); vis[i]=0; } } } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&str[i][j]); for(int i=2;i<=n;i++) scanf("%d",&dd[i]); floyd(); memset(vis,0,sizeof(vis)); ans=inf; dfs(1,0,0,n-1); if(ans == inf )printf("-1 "); else printf("%d ",ans); } }
双向bfs
题意:erriye 梦见女友被困在迷宫里了,现在 erriye 需要去解救他的的女友 给出他女友和他的位置
题意:迷宫里有两个ghost,每秒钟会分生出多个ghost占据在他2步之内的所有格子
little erriye 每秒可以移动3步,grilfriend每秒可以移动一步
ghost、erriye、grilfriend都只能上下左右移动(且人不能穿透墙壁,鬼魂可以)
题意:人一旦与鬼魂占据同一格子,则被杀死
题意:问:little erriye 最少需要多久才能解救其女友?(如果解救失败,输出-1)
#include<bits/stdc++.h> using namespace std; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; char str[802][802]; int vis[2][802][802];//标记路径 int n,m,step; struct node{ int x,y; }ss,ee,z[2]; queue<node>q[2]; void init() { int cnt=0; cin>>n>>m; for(int i=0;i<n;i++) { scanf("%s",str[i]); for(int j=0;j<m;j++) { if(str[i][j]=='M') ss.x=i,ss.y=j; else if(str[i][j]=='G') ee.x=i,ee.y=j; else if(str[i][j]=='Z') z[cnt].x=i,z[cnt++].y=j; } } } int judge(node b) { if(b.x<0||b.y<0||b.x>=n||b.y>=m||str[b.x][b.y]=='X') return 0; if(abs(b.x-z[0].x)+abs(b.y-z[0].y)<=2*step)//判断是否撞鬼 return 0; if(abs(b.x-z[1].x)+abs(b.y-z[1].y)<=2*step) return 0; return 1; } int bfs(int w) { node now,next; int sum; sum=q[w].size(); while(sum--) { now=q[w].front(); q[w].pop(); if(judge(now)==1) { for(int i=0;i<4;i++) { next.x=now.x+dx[i]; next.y=now.y+dy[i]; if(judge(next)==1&&vis[w][next.x][next.y]==0) { if(vis[w^1][next.x][next.y]==1)//解救成功条件是这条路是另一个人走过的 return 1; vis[w][next.x][next.y] = 1; q[w].push(next); } } } } return -1; } int solve() { while(!q[0].empty())q[0].pop(); while(!q[1].empty()) q[1].pop(); q[0].push(ss); q[1].push(ee); memset(vis,0,sizeof(vis)); vis[0][ss.x][ss.y]=vis[1][ee.x][ee.y]=1; step=0; while((!q[0].empty())||(!q[1].empty())) { step++; if(bfs(0)==1) return step; if(bfs(0)==1) return step; if(bfs(0)==1) return step; if(bfs(1)==1) return step; } return -1; } int main() { int tt; cin>>tt; while(tt--) { init(); cout<<solve()<<endl; } return 0; }
hdu6383
http://acm.hdu.edu.cn/showproblem.php?pid=6383
题目大意:给你一堆数字,可以随便找两个,一个+1,一个-2,使最后形成的数列最大值和最小值相差为1,求最小值的最大值
#include<bits/stdc++.h> using namespace std; long long a[10000020]; int main() { long long t; scanf("%lld",&t); while(t--) { long long n; scanf("%lld",&n); long long l=0x3f3f3f3f,r=-1; for(int i=0;i<n;i++) { scanf("%lld",&a[i]); l=min(l,a[i]); r=max(r,a[i]); } long long mid=0,ans=-1; while(l<=r)//注意不要l<r会死循环 { mid=(l+r)>>1; long long up=0,down=0; for(int i=0;i<n;i++) { if(a[i]<mid)up+=mid-a[i]; else if(a[i]>mid) down+=(a[i]-mid)>>1; } if(up<=down)//降得情况要大于升的情况,因为降我可以+1,-2,让后-2,+1,这样两个数就都减一,然而升的话只能+1+1的升 { l=mid+1; ans=max(ans,mid); } else r=mid-1; } printf("%lld ",ans); } }
poj1064
http://poj.org/problem?id=1064
经典的割绳子问题
n段绳子,我要m段,问能割的最长长度
#include<iostream> #include<math.h> #include<stdio.h> #include<string.h> double a[10010]; const double eps=0.00000001; int n,m; int judge(double x) { int ans=0; for(int i=0;i<n;i++) ans+=(int)(a[i]/x); if(ans>=m) return 1; else return 0; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<n;i++) scanf("%lf",&a[i]); double l=0,r=100001; double t=0; while(r-l>=eps) { double mid=(l+r)/2; if(judge(mid))l=mid; else r=mid; } printf("%.2lf ",floor(r*100)/100); } }
hdu3746
给一个字符串,看缺几个可以构成循环
kmp算法循环节裸题,先上模板
void getnext() { int i=0,j=-1; next[0]=-1; while(i<tlen) { if(j==-1||t[i]==t[j]) next[++i]=++j; else j=next[j]; } } int kmp_index()//统计出现位置 { int i=0,j=0; getnext(); while(i<slen && j<tlen) { if(j==-1 ||s[i]==t[j])//匹配成功则往下找 i++;j++; else //否则把t字符串往前移动 j=next[j]; } if(j==tlen) return i-tlen; else return -1; } int kmp_count()//统计出现次数 { int ans=0,i=0,j=0; while(i<slen) { if(j==-1||s[i]==t[j])//同上 i++,j++; else j=next[j]; if(j==tlen)//判断是否有了 { ans++; j=next[j]; } } return ans; }
代码
#include<iostream> #include<string.h> using namespace std; int nextt[1000005]; char a[100002]; void getnext() { int i=0,j=-1; nextt[0]=-1; int t=strlen(a); while(i<t) { if(j==-1 || a[i]==a[j]) nextt[++i]=++j; else j=nextt[j]; } } int main() { int n; scanf("%d",&n); while(n--) { scanf("%s",a); getnext(); int t=strlen(a); if(t%(t-nextt[t])==0&&nextt[t]!=0) printf("0 "); else printf("%d ",(t-nextt[t])-t%(t-nextt[t]));//该字符串长度减去next[末尾]为循环节长度 } }
codeforces
http://codeforces.com/contest/1008/problem/D
给一个长方体,判断是否可以刚好由几个相同的小长方体填满
题解https://blog.csdn.net/weixin_42165981/article/details/81212814
https://blog.csdn.net/codeswarrior/article/details/81146331
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5+10; ll C(int n,int m){//求组合数 ll ans = 1; for(int i = 1; i <= m; i++){ ans = ans * (n-i+1) / i; } return ans; } bool check(int a,int b,int c){//如果111 if((a & 1) && (b & 2) && (c & 4)) return true; if((a & 1) && (c & 2) && (b & 4)) return true; if((b & 1) && (a & 2) && (c & 4)) return true; if((b & 1) && (c & 2) && (a & 4)) return true; if((c & 1) && (a & 2) && (b & 4)) return true; if((c & 1) && (b & 2) && (a & 4)) return true; return false; } int gcd(int a,int b){ if(b == 0) return a; return gcd(b,a%b); } int cnt[10],use[10]; int fac[maxn]; int main(){ //???????????? for(int i = 1; i < maxn; i++){//通过打表来记录每个数的因子个数 for(int j = i; j < maxn; j += i){ fac[j]++; } } int t,x,y,z; ll ans; scanf("%d",&t); while(t--){ scanf("%d%d%d",&x,&y,&z); int xy = gcd(x,y); int yz = gcd(y,z); int xz = gcd(x,z); int xyz = gcd(xy,z); //容斥原理 cnt[7] = fac[xyz];//111 cnt[6] = fac[yz] - fac[xyz];//110 cnt[5] = fac[xz] - fac[xyz];//101 cnt[4] = fac[z] - fac[xz] - fac[yz] + fac[xyz];//100 cnt[3] = fac[xy] - fac[xyz];//011 cnt[2] = fac[y] - fac[xy] - fac[yz] + fac[xyz];//010 cnt[1] = fac[x] - fac[xy] - fac[xz] + fac[xyz];//001 ans = 0; for(int a = 1; a < 8; a++){ for(int b = a; b < 8; b++){ for(int c = b; c < 8; c++){ if(check(a,b,c)){ memset(use,0,sizeof(use)); use[a]++; use[b]++; use[c]++;//??????????????? ll tmp = 1; for(int i = 1; i < 8; i++){// if(use[i]) tmp *= C(cnt[i]+use[i]-1,use[i]); } if(tmp > 0) ans += tmp; } } } } cout<<ans<<endl; } return 0; }
http://codeforces.com/contest/1008/problem/C
题意给n个数,移动位置后算出最大的数(移动后的数字比以前大的个数)
#include<bits/stdc++.h> using namespace std; int a[100002],b[100002]; int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; sort(a,a+n); int k=0; int ans=0; for(int i=0;i<n;i++) { while(k<=n&&a[k]<=a[i])//找出第一个比第i个数大的 k++; if(k<=n) ans++,k++; } cout<<ans<<endl; return 0; }
http://codeforces.com/contest/1008/problem/B
题意:给了n个矩形的长和宽,可以翻转每一个矩形,也就是交换长和宽,让矩形的长或者宽形成非递增排列。
#include<bits/stdc++.h> using namespace std; long long a[100002],b[100002],ans[100002]; int main() { int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]>>b[i]; ans[0]=max(a[0],b[0]); int k=1; for(int i=1;i<n;i++) { int t1=max(a[i],b[i]); int t2=min(a[i],b[i]); if(ans[i-1]>=t1) ans[i]=t1; else if(ans[i-1]>=t2) ans[i]=t2; else if(ans[i-1]<t2){ //cout<<i<<" "<< cout<<"NO"<<endl; return 0; } } cout<<"YES"<<endl; return 0; }
http://codeforces.com/contest/1011/problem/B
题目大意:n个人m个食物,每个食物都有种类,每个人只能吃一种食物(无论哪一种),求最多能活多少天。
#include<bits/stdc++.h> using namespace std; int a[105],b[105]; int main() { int m,n; cin>>m>>n; memset(b,0,sizeof(b)); for(int i=0;i<n;i++) { cin>>a[i]; b[a[i]]++; } //for(int i=0;i<10;i++) cout<<b[i]<<endl; if(m>n) cout<<"0"<<endl; else { int ans=1; for(int i=2;i<=100;i++) { int t=0; for(int j=1;j<=100;j++) { t+=b[j]/i; //cout<<t<<" "; if(t>=m){ ans=max(ans,i); break; } } } cout<<ans<<endl; } return 0; }
http://codeforces.com/contest/1011/problem/C
给你飞机初始重量,飞机要在所有机场起飞降落。一开始会携带一定重量的汽油,然后每次飞的过程会消耗掉相应汽油,而每个机场给的值是1吨汽油能让他飞多少。
#include<bits/stdc++.h> using namespace std; int n,m; int a[1005],b[1005]; const long long eps=0.0000001; double jisuan(double x) { x-=(m+x)/a[0]; for(int i=1;i<n;i++) { if(x<0) return -1; x-=(m+x)/b[i]; if(x<0) return -1; x-=(m+x)/a[i]; } if(x<0) return -1; x-=(m+x)/b[0]; if(x<0) return -1; else if (x>0) return 1; else return 0; } int main() { cin>>n>>m; for(int i=0;i<n;i++) { cin>>a[i]; if(a[i]==1) { cout<<-1<<endl; exit(0); } } for(int i=0;i<n;i++) { cin>>b[i]; if(b[i]==1) { cout<<-1<<endl; exit(0); } } double l=1,r=1000000000; double t=0; while(r-l>=eps) { t++; if(t==62) { printf("%.7lf",(l+r)/2); return 0; } double m=(l+r)/2; if(jisuan(m)<0) l=m; else if(jisuan(m)>0) r=m; } printf("%.7lf",(l+r)/2); }
今天突然有些新的想法,想要说些什么却不知道从何说起,有一种莫名的兴奋和激动,或许是觉得要想改变自己。
我觉得以后没事写点东西还是挺好的,记录下自己的思想的转变,还有,要学会独立思考,这我觉得很重要