目录
!L2-001 城市间紧急救援 - Dijkstra运用
思路:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=510;
int n,m,s,d;
int g[N][N];
int dist[N],w[N],sumw[N],road[N],pre[N];
int prt[N],cnt=0;
bool st[N];
void dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[s]=0;
sumw[s]=w[s]; //救援队数目
road[s]=1; //最短路径的条数
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=0;j<n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
st[t]=true;
for(int j=0;j<n;j++)
{
if(dist[j]>dist[t]+g[t][j]) //选最短路径
{
dist[j]=dist[t]+g[t][j];
road[j]=road[t]; //不理解
sumw[j]=sumw[t]+w[j];
pre[j]=t;
}
else if(dist[j]==dist[t]+g[t][j])
{
road[j]+=road[t]; //不理解
if(sumw[j]<sumw[t]+w[j])
{
sumw[j]=sumw[t]+w[j];
pre[j]=t;
}
}
}
}
cout<<road[d]<<' '<<sumw[d]<<endl;
//把经过的点倒序输出
cout<<s;
for(int i=d;i!=s;i=pre[i])
prt[cnt++]=i;
reverse(prt,prt+cnt);
for(int i=0;i<cnt;i++)
cout<<' '<<prt[i];
}
int main()
{
cin>>n>>m>>s>>d;
for(int i=0;i<n;i++) cin>>w[i];
memset(g,0x3f,sizeof g);
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=c;
}
dijkstra();
return 0;
}
!L2-002 链表去重 - 链表模拟
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
using namespace std;
const int N=1e5+10;
int head,n;
int e[N],ne[N];
bool st[N];
int main()
{
cin>>head>>n;
while(n--)
{
int idx,w,next;
cin>>idx>>w>>next;
e[idx]=w,ne[idx]=next;
}
vector<int>re,unre; //re存重复元素 unre存不重复元素
for(int i=head;i!=-1;i=ne[i])
{
int x=abs(e[i]);
if(!st[x])
{
st[x]=true;
unre.push_back(i);
}else re.push_back(i);
}
//输出去重的链表
for(int i=0;i<unre.size();i++)
{
printf("%05d %d",unre[i],e[unre[i]]);
if(i==unre.size()-1) puts(" -1");
else printf(" %05d\n",unre[i+1]);
}
//输出删去的链表
for(int i=0;i<re.size();i++)
{
printf("%05d %d",re[i],e[re[i]]);
if(i==re.size()-1) puts(" -1");
else printf(" %05d\n",re[i+1]);
}
return 0;
}
!L2-003 月饼 - 结构体+重载运算符+排序
思路:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
using namespace std;
const int N=1010;
int n;
double d,res=0;
struct node
{
double w,p;
bool operator<(const node &t)const //按照单价由大到小排序
{
return p/w>t.p/t.w;
}
}a[N];
int main()
{
cin>>n>>d;
for(int i=0;i<n;i++) cin>>a[i].w;
for(int i=0;i<n;i++) cin>>a[i].p;
sort(a,a+n);
for(int i=0;i<n&&d>0;i++)
{
if(a[i].w<=d)
{
d-=a[i].w;
res+=a[i].p;
}else
{
res+=a[i].p/a[i].w*d;
break;
}
//这个办法很妙↓
/*double r=min(d,a[i].w);
d-=r;
res+=a[i].p/a[i].w*r;*/
}
printf("%.2f\n",res);
return 0;
}
!L2-004 这是二叉搜索树吗?- 建二叉树模板题
思路:
#include <iostream>
#include <malloc.h>
using namespace std;
const int N=1010;
int n,a[N];
int p1[N],p2[N];
int cnt1=0,cnt2=0;
bool flag;
typedef struct node
{
int data;
node *l,*r;
}node,*tree;
tree create1(tree T,int x)
{
if(!T)
{
T=(tree)malloc(sizeof(node));
T->l=nullptr,T->r=nullptr;
T->data=x;
}
else
{
if(T->data>x) T->l=create1(T->l,x);
else if(T->data<=x) T->r=create1(T->r,x);
}
return T;
}
tree create2(tree T,int x)
{
if(!T)
{
T=(tree)malloc(sizeof(node));
T->l=nullptr,T->r=nullptr;
T->data=x;
}
else
{
if(T->data<=x) T->l=create2(T->l,x);
else if(T->data>x) T->r=create2(T->r,x);
}
return T;
}
void pre1(tree T)
{
if(!T) return;
p1[cnt1++]=T->data;
pre1(T->l);
pre1(T->r);
}
void pre2(tree T)
{
if(!T) return;
p2[cnt2++]=T->data;
pre2(T->l);
pre2(T->r);
}
void post(tree T)
{
if(!T) return;
post(T->l);
post(T->r);
if(flag) cout<<' ';
flag=true;
cout<<T->data;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
//创建二叉搜索树
tree T1=nullptr;
for(int i=0;i<n;i++) T1=create1(T1,a[i]);
//创建镜像二叉搜索树
tree T2=nullptr;
for(int i=0;i<n;i++) T2=create2(T2,a[i]);
//分非镜像和镜像进行前序遍历 和原序列进行比较
pre1(T1),pre2(T2);
bool f1=false,f2=false;
for(int i=0;i<n;i++) if(p1[i]!=a[i]) f1=true;
for(int i=0;i<n;i++) if(p2[i]!=a[i]) f2=true;
if(f1&&f2) cout<<"NO";
else if(!f1&&f2) puts("YES"),post(T1);
else if(f1&&!f2) puts("YES"),post(T2);
else if(!f1&&!f2) puts("YES"),post(T1);
return 0;
}
L2-005 集合相似度 - set容器去重应用
#include <iostream>
#include <set>
using namespace std;
const int N=1e4+10;
int n,m,k;
int main()
{
set<int>s[N];
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
while(m--)
{
int x;
cin>>x;
s[i].insert(x);
}
}
cin>>k;
while(k--)
{
int a,b,cnt=0;
cin>>a>>b;
for(auto x:s[a]) if(s[b].count(x)) cnt++;
printf("%.2f%%\n",cnt*1.0/(s[a].size()+s[b].size()-cnt)*100);
}
return 0;
}
L2-006 树的遍历 - 中后序遍历构建树+层序遍历
思路: 这题思路跟L2-011 玩转二叉树一模一样啊 就是板子题
- 通过中后序构建树
- 层序遍历
#include <iostream>
#include <malloc.h>
#include <queue>
using namespace std;
const int N=35;
int n;
int po[N],mid[N];
typedef struct node
{
int data;
node *l,*r;
}node,*tree;
tree reback(int len,int *po,int *mid) //通过中序和后序遍历还原前序遍历
{
if(len<=0) return NULL;
tree T=(tree)malloc(sizeof(node));
T->l=T->r=NULL;
T->data=po[len-1]; //后序遍历的最后一个点为前序遍历根节点
int i=0;
for(i=0;i<len;i++)
if(T->data==mid[i]) break; //在中序遍历里找到树根 记录i
T->l=reback(i,po,mid);
T->r=reback(len-1-i,po+i,mid+i+1);
return T;
}
void bfs(tree T)
{
bool flag=false;
queue<tree>q;
q.push(T);
while(q.size())
{
auto t=q.front();
q.pop();
if(flag) cout<<' ';
flag=true;
cout<<t->data;
if(t->l)q.push(t->l);
if(t->r)q.push(t->r);
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>po[i];
for(int i=0;i<n;i++) cin>>mid[i];
tree T=reback(n,po,mid);
bfs(T);
return 0;
}
!L2-007 家庭房产 - 并查集+结构体+排
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
int f[N];
map<int,bool>st;
struct peo
{
int id;
double cnt,area;
}p[N];
struct family
{
int anc=-1,num;
double cnt,area,avg_cnt,avg_area;
}fam[N];
int find(int x)
{
if(x!=f[x]) f[x]=find(f[x]);
return f[x];
}
void unite(int a,int b)
{
int x=find(a);
int y=find(b);
if(x!=y) f[x]=y;
}
bool cmp(family a,family b) //家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
{
if(a.avg_area!=b.avg_area)
return a.avg_area>b.avg_area;
else return a.anc<b.anc;
}
int main()
{
for(int i=0;i<N;i++) f[i]=i;
cin>>n;
for(int i=0;i<n;i++)
{
int id,fa,ma;
cin>>id>>fa>>ma;
st[id]=true;
if(fa!=-1) st[fa]=true,unite(id,fa);
if(ma!=-1) st[ma]=true,unite(id,ma);
int k;
cin>>k;
while(k--)
{
int x;
cin>>x;
unite(x,id);
st[x]=true;
}
int cnt,area;
cin>>cnt>>area;
p[id].cnt=cnt,p[id].area=area;
}
for(auto x:st)
{
fam[find(x.first)].cnt+=p[x.first].cnt;
fam[find(x.first)].area+=p[x.first].area;
if(fam[find(x.first)].anc==-1) fam[find(x.first)].anc=x.first;
fam[find(x.first)].num++;
}
for(int i=0;i<N;i++)
{
if(!st[i])continue;
fam[find(i)].avg_cnt=fam[find(i)].cnt/fam[find(i)].num;
fam[find(i)].avg_area=fam[find(i)].area/fam[find(i)].num;
}
int sum=0;
for(int i=0;i<N;i++) if(fam[i].num) sum++;
cout<<sum<<endl;
sort(fam,fam+N,cmp);
for(int i=0;i<sum;i++)
printf("%04d %d %.3f %.3f\n",fam[i].anc,fam[i].num,fam[i].avg_cnt,fam[i].avg_area);
return 0;
}
!L2-008 最长对称子串 - 字符串+暴力+双指
getline和cin区别
getline——按行读取, 一次读取多个字符,直到读满N个(不包括空白符)为止。
形式:getline(字符指针,字符个数N,结束符);cin——遇到结束符(包括空白符)会终止,只读取空白符之前的部分。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int main()
{
int res=0;
string s;
getline(cin,s); //不能用cin cin遇到空格就截止
for(int i=0;i<s.size();i++)
for(int j=s.size()-1;j>=i;j--)
{
int l=i,r=j;
while(l<=r&&s[l++]==s[r--])
if(l>r) res=max(res,j-i+1);
}
cout<<res<<endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
string s;
int main()
{
getline(cin,s);
for(int len=s.size();len>0;len--) //找最大长度 倒序找
for(int l=0;l+len-1<s.size();l++)
{
bool f=false;
int i=l,j=l+len-1;
while(i<j)
{
if(s[i]!=s[j])
{
f=true;
break;
}
i++,j--;
}
if(!f)
{
cout<<len<<endl;
return 0;
}
}
}
L2-009 抢红包 - 模拟+排序
思路:
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
struct node
{
int id;
double qiang_w,fa_w,res;
int qiang_count;
}a[N];
bool cmp(node a,node b)
{
if(a.res!=b.res) return a.res>b.res;
else if(a.qiang_count!=b.qiang_count) return a.qiang_count>b.qiang_count;
else return a.id<b.id;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) a[i].id=i;
for(int i=1;i<=n;i++)
{
int k;
cin>>k;
for(int j=1;j<=k;j++)
{
int id,w;
cin>>id>>w;
a[id].qiang_w+=w;
a[id].qiang_count++;
a[i].fa_w+=w;
}
}
for(int i=1;i<=n;i++) a[i].res=a[i].qiang_w-a[i].fa_w;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++) printf("%d %.2f\n",a[i].id,a[i].res*1.0/100);
return 0;
}
L2-010 排座位
思路:
#include <bits/stdc++.h>
using namespace std;
const int N=110;
int g[N][N];
int n,m,k;
bool check(int a,int b)
{
for(int i=1;i<=n;i++)
if(g[a][i]==1&&g[b][i])
return true;
return false;
}
int main()
{
cin>>n>>m>>k;
while(m--)
{
int a,b,r;
cin>>a>>b>>r;
g[a][b]=g[b][a]=r;
}
while(k--)
{
int a,b;
cin>>a>>b;
if(g[a][b]==1) puts("No problem");
else if(g[a][b]==0) puts("OK");
else if(g[a][b]==-1&&check(a,b)) puts("OK but...");
else puts("No way");
}
return 0;
}
L2-011 玩转二叉树 - 前中序遍历构建树+层序遍历
思路: 和L2-006 树的遍历一模一样
- 先通过中序遍历和前序遍历确定出树 因为题目要求左右子树对调 所以递归构建的时候反一下就可以了
- 然后用队列进行层序遍历 根节点入队 然后根节点的左右结点入队 每次取队头输出然后扔掉
#include <bits/stdc++.h>
using namespace std;
const int N=55;
int mid[N],pre[N];
typedef struct node
{
int data;
node *l,*r;
}node,*tree;
tree create(int len,int *mid,int *pre)
{
if(!len) return NULL;
tree T=NULL;
T=(tree)malloc(sizeof(struct node));
T->l=T->r=NULL;
T->data=pre[0]; //前序遍历的第一个是根节点
int i=0;
for(i=0;i<len;i++) //让i指针定位到中序遍历的根节点位置 !这里注意不能int i=0 要不然记录不了i值
if(mid[i]==T->data) break;
//因为要镜面翻转:左右子树互换
T->r=create(i,mid,pre+1);
T->l=create(len-(i+1),mid+i+1,pre+i+1);
return T;
}
void bfs(tree T)
{
queue<tree>q;
q.push(T);
bool f=false;
while(!q.empty())
{
auto t=q.front();
q.pop();
if(f) cout<<' ';
f=true;
if(t->l) q.push(t->l);
if(t->r) q.push(t->r);
cout<<t->data;
}
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>mid[i];
for(int i=0;i<n;i++) cin>>pre[i];
tree T=create(n,mid,pre);
bfs(T);
return 0;
}
✓L2-012 关于堆的判断 - 优先队列+哈希表
大顶堆:每个结点的值都大于或等于其左右孩子结点的值;
小顶堆:每个结点的值都小于或等于其左右孩子结点的值。
思路:
- 用优先队列PriorityQueue来实现小顶堆
- 把小顶堆转化为数组 并更改数组下标从1开始 这样idx/2就是父节点
- 用map存 < 结点值,下标 >
- 逐步实现四个查询步骤即可 详见代码
import java.util.*;
public class Main{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
Queue<Integer>q=new PriorityQueue<>();
Map<Integer,Integer> mp=new HashMap<>();
String s;
for(int i=0;i<n;i++)
q.offer(sc.nextInt());
//把优先队列(小顶堆)转化到数组
Integer[] t=q.toArray(new Integer[n]);
int[] a=new int[n+1]; //因为索引从1开始 所以是n+1
int cnt=1;
//修改数组索引从1开始 这样idx/2就是父结点
for(int i=0,j=1;i<n;i++)
a[j++]=t[i].intValue();
for(int i=1;i<=n;i++)
{
mp.put(a[i],cnt);
cnt++;
}
sc.nextLine(); //接收回车
while(m-->0)
{
boolean f=false;
s=sc.nextLine();
String[] str=s.split(" ");
if(s.indexOf("root")!=-1)
{
int root=Integer.parseInt(str[0]);
if(mp.get(root)==1) f=true;
}else if(s.indexOf("siblings")!=-1)
{
int l=Integer.parseInt(str[0]);
int r=Integer.parseInt(str[2]);
l=mp.get(l);
r=mp.get(r);
if(l/2==r/2) f=true;
}else if(s.indexOf("parent")!=-1)
{
int parent=Integer.parseInt(str[0]);
int child=Integer.parseInt(str[5]);
if(mp.get(child)/2==mp.get(parent)) f=true;
}else{
int child=Integer.parseInt(str[0]);
int parent=Integer.parseInt(str[5]);
if(mp.get(child)/2==mp.get(parent)) f=true;
}
if(f) System.out.println("T");
else System.out.println("F");
}
}
}