目录
前言
趁
xmq
x
m
q
不再,第一水过。。。
然而只有260。。。
总结
学了
LCA
L
C
A
。。。
然后,就没有然后了。。。
放几篇博文吧。。。
商务旅行(倍增和tarjan做法皆有)
POJ 1330(LCA板子题,不过本人只用了tarjan做)
货车运输(算是一道比较难的LCA的题了,值得一刷)
题目
第一题 最大面积
大意
给定一个半径为 r r 的圆,放入两个长为,宽为 b b 的长方形,问在面积最大的情况下可以得到最大的和 b b
思路
利用勾股定理暴力模拟
代码
空间复杂度:
时间复杂度:
O(2r)
O
(
2
r
)
#include<cstdio>
#include<cmath>
#define sqr(x) (x*x)
using namespace std;int n,a,b;double tmpi,tmpj,best,tmp;
int main()
{
scanf("%d",&n);n*=2;
for(int i=1;i<n;i++)
for(int j=1;j<n;j++)
{
tmpi=sqrt(sqr(n/2.0)-sqr(i/2.0))*2;
tmpj=sqrt(sqr(n/2.0)-sqr(j/2.0))*2;//勾股定理计算小长方形的长和宽
tmp=tmpi*i+tmpj*j-i*j;//计算面积
if(tmp>best)
{
best=tmp;
a=i;
b=j;//保存最优解
}
}
printf("%d\n%d",a,b);//输出
}
第二题 文件名排序
大意
排序
思路
排序
(什么排序都行,因为它数据是真的弱)
代码(string)
该算法的优势就是比较时更为方便
#include<cstdio>
#include<iostream>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#define check1 (a[i].d<a[j].d)
#define check2 (a[i].d==a[j].d&&a[i].d==1&&a[i].kzm>a[j].kzm)
#define check3 (a[i].d==a[j].d&&a[i].d==1&&a[i].kzm==a[j].kzm&&a[i].wjm>a[j].wjm)
#define check4 (a[i].d==a[j].d&&!a[i].d&&a[i].wjm>a[j].wjm)//四种情况,题目当中有
using namespace std;int n,k;string s;
struct node
{
string wjm,kzm;
bool d;
int xh,rank;
}a[101];
bool cmp(node x,node y){return x.xh<y.xh;}
int main()
{
file(sort);
scanf("%d\n",&n);
for(int i=1;i<=n;i++)
{
cin>>s;k=-1;
k=s.find('.');
if(k!=-1)
{
a[i].wjm=s.substr(0,k);//保存文件名
a[i].d=true;//标记有点
a[i].kzm=s.substr(k+1,s.size()-a[i].wjm.size()-1);//扩展名
}
else
a[i].wjm=s;//没有扩展名
a[i].xh=i;
}
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(check1||check2||check3||check4)
swap(a[i],a[j]);//第一遍冒泡
for(int i=1;i<=n;i++) a[i].rank=i;//保存排名
sort(a+1,a+1+n,cmp);//重新排序
for(int i=1;i<=n;i++) printf("%d\n",a[i].rank);//输出
}
代码(Cstring)
该算法的优势是速度更快,调试更轻松
时间复杂度:
O(nlogn+n2)
O
(
n
l
o
g
n
+
n
2
)
空间复杂度:
O(
O
(
很大
)
)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
using namespace std;int n,k,x,y,len1,len2;bool d;
struct node
{
char wjm[101],kzm[101],s[101];
int xh,rank;
}a[101];
bool cmp(node x,node y){return x.xh<y.xh;}
int check(char a[],char b[])
{
for(int i=0;i<min(strlen(a),strlen(b));i++)
if(a[i]<b[i]) return -1;//不需交换
else if(a[i]>b[i]) return 1;//需要交换
if(strlen(a)<strlen(b)) return -1;//不需要交换
if(strlen(a)==strlen(b)) return 0;//完全相等
return 1;//需要交换
}
int find(char c,char s[])//查找点的位置
{
for(int i=0;i<strlen(s);i++) if(s[i]==c) return i;
return 0;
}
int main()
{
file(sort);
scanf("%d\n",&n);
for(int i=1;i<=n;i++)
{
gets(a[i].s);d=0;len1=0;len2=0;
for(k=0;k<strlen(a[i].s);k++)
{
if(d) a[i].kzm[len2++]=a[i].s[k];
if(a[i].s[k]=='.') d=1;
if(!d) a[i].wjm[len1++]=a[i].s[k];
}
a[i].xh=i;
}
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
x=find('.',a[i].s);
y=find('.',a[j].s);
int hz=check(a[i].kzm,a[j].kzm),qz=check(a[i].wjm,a[j].wjm);
if(!x&&y) {swap(a[i],a[j]);continue;}//有扩展名的优先
if(x&&y)
{
if(hz==-1) continue;//不需交换直接返回
if(hz==1) {swap(a[i],a[j]);continue;}//交换
if(qz==1) swap(a[i],a[j]);continue;//交换
}
if(!x&&!y&&qz==1) swap(a[i],a[j]);//交换
}
for(int i=1;i<=n;i++) a[i].rank=i;
sort(a,a+1+n,cmp);//记得还要排一次
for(int i=1;i<=n;i++) printf("%d\n",a[i].rank);
}
第三题 取数
思路
暴搜80(好像某人A了)
记搜
就是把滑雪的记搜方法改一下,因为它有这种情况
1 1
3 2
5 0
7 0
9 0
如果是滑雪的方法它会把3堵住导致并非最优解,所以我们对记搜数组做一个新的参数——方向,比如上面那个我们既可以记录为左边和下边,这样子就可以避免封路带来的不优化性,就可以达到动态规划的目的啦!
代码(暴搜)
空间复杂度:
O(n2)
O
(
n
2
)
时间复杂度:
O(4n4)
O
(
4
n
4
)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
using namespace std;int n,m,a[101][101],ans=1,now,tot;
bool vis[101][101];//标记数组,如果用这个就会超时,不用就会WA
const short dx[4]={-1,0,1,0};
const short dy[4]={0,1,0,-1};//四个方向
int read()
{
int d=1,f=0;char c;
while((c=getchar())<48||c>57) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
void write(int x)
{
if(x>9) write(x/10);putchar(x%10+48);return;
}
int dfs(int x,int y,int c)//暴力搜索
{
if(vis[x][y]==tot||x<1||y<1||x>n||y>m||c<=0) return 0;
int t=1;vis[x][y]=tot;
for(int i=0;i<4;i++)
if(c==a[x+dx[i]][y+dy[i]]-a[x][y])
{t=max(t,dfs(x+dx[i],y+dy[i],c)+1);}//四个方向
return t;
}
int main()
{
file(pick);
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) a[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
if(a[i+dx[k]][j+dy[k]]-a[i][j]>0)
{tot++;ans=max(ans,dfs(i,j,a[i+dx[k]][j+dy[k]]-a[i][j]));if(now==n*m) break;}//暴力搜索
write(ans);
}
代码(记搜)
时间复杂度:
O(4n2)
O
(
4
n
2
)
空间复杂度:
O(4n2)
O
(
4
n
2
)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define check(x,y) (x<1||y<1||x>n||y>m)
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
using namespace std;int n,m,a[101][101],ans=1,now,tot,f[101][101][4];//记忆化
const short dx[4]={-1,0,1,0};
const short dy[4]={0,1,0,-1};//四个方向
int read()
{
int d=1,f=0;char c;
while((c=getchar())<48||c>57) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
void write(int x)
{
if(x>9) write(x/10);putchar(x%10+48);return;
}
int len(int x,int y,int dep)//计算它们之间的落差
{
int nx=x+dx[dep],ny=y+dy[dep];
if(check(nx,ny)) return 99999999;
return abs(a[nx][ny]-a[x][y]);
}
void dfs(int x,int y,int dep)
{
if(check(x,y)) return;//暴出范围推出
if(f[x][y][dep]) return;//返回
f[x][y][dep]=1;//最少长度为1
int nx=x+dx[dep],ny=y+dy[dep];
if(a[nx][ny]<=a[x][y]) return;//落差为负数,返回
for(int i=0;i<4;i++)
{
dfs(nx,ny,i);
if(len(nx,ny,i)!=len(x,y,dep)) continue;//隔差不等返回
f[x][y][dep]=max(f[x][y][dep],f[nx][ny][i]+1);//保存最优解
}
return;
}
int main()
{
file(pick);
n=read();m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) a[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
{
dfs(i,j,k);//继续搜索
ans=max(ans,f[i][j][k]);//保存最优解
}
write(ans);
}
第四题 航空公司
大意
求一张有向图的最小生成树中的最长边
思路
库鲁思卡尔或者
prim
p
r
i
m
算法
(本题
prim
p
r
i
m
更快)
代码
时间复杂度:
O(n2logn2+n2)
O
(
n
2
l
o
g
n
2
+
n
2
)
空间复杂度:
O(n2)
O
(
n
2
)
#include<algorithm>
#include<cstdio>
#include<cmath>
#define N 1001
#define min(a,b) a<b?a:b
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
using namespace std;int n,x[N],y[N],r[N],tot,f[N],k=0;double ans;
struct node{int from,to;double w;}edge[N*N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void judge(int x,int y){f[find(x)]=find(y);return;}
bool check(int x,int y){return find(x)==find(y);}
void add(int u,int v)
{
edge[++tot].from=u;
edge[tot].to=v;
edge[tot].w=sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]))-r[u]-r[v];//勾股定理算距离
}
bool cmp(node x,node y)
{
return x.w<y.w;
}
int read()
{
int d=1,f=0;char c;
while((c=getchar())<48||c>57) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while((c=getchar())>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
int main()
{
file(air);
n=read();
for(int i=1;i<=n;i++) x[i]=read(),y[i]=read(),r[i]=read(),f[i]=i;
for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++) add(i,j);
sort(edge+1,edge+1+tot,cmp);
for(int i=1;i<=tot&&k<n;i++)
if(!check(edge[i].from,edge[i].to))
{
k++;
judge(edge[i].from,edge[i].to);//并查集合并
ans=max(ans,edge[i].w);//保存最长边
}
if(ans!=floor(ans)) ans=floor(ans)+1;
printf("%0.lf",ans);
}