L2刷题记录

L2-001 紧急救援(dijktstra+路径输出)

在这里插入图片描述

#include<bits/stdc++.h>
#include<string.h>
using namespace std;
int a[510][510];
int num[510]; // 每个城市的救援数 
int sum[510]; //总的救援队 
int dis[510]; //距离 
bool vis[510];
int pre[510];//前驱 
int cnt[510];//方案数 
const int inf = 0x3f3f3f3f;
int n,m,s,d;
	
void init(){
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			if(i == j){
				a[i][j] = 0;
			}else{
				a[i][j] = inf;
			}
		}
	}
}	
	
void dijkstra(int s){
	cnt[s] = 1;
	dis[s] = 0;
	sum[s] = num[s];
	for(int i = 0; i < n; i++){
		int mini = inf;
		int mi = -1;
		for(int j = 0; j < n; j++){
			if(!vis[j] && dis[j] < mini){
				mini = dis[j];
				mi = j;
			}
		}
		if(mi == -1) break;
		vis[mi] = true;
		for(int j = 0; j < n; j++){
			if(!vis[j]){
				if(dis[j] > dis[mi] + a[mi][j]){ //如果找到一条路径更短的则
					dis[j] = dis[mi] + a[mi][j];
					sum[j] = sum[mi] + num[j];
					cnt[j] = cnt[mi];
					pre[j] = mi;
				}else if(dis[j] == dis[mi] + a[mi][j]){
					cnt[j] = cnt[mi] + cnt[j];
					if(sum[j] < sum[mi] + num[j]){
						sum[j] = sum[mi] + num[j];
						pre[j] = mi;
					}
				}
			}
		}
	}
		
}

void path(int d){
	if(pre[d] != -1) {
		path(pre[d]);
		printf("%d ", pre[d]);
	}
}
void display(int d){
	cout << cnt[d] << " " << sum[d] << endl;
    path(d);
    cout << d << endl;
}

int main(){
	cin >> n >> m >> s >> d;
	init();
	for(int i = 0; i < n; i++){
		cin >> num[i];
	}
	for(int i = 1; i <= m; i++){
		int x,y,w;
		cin >> x >> y >> w;
		a[x][y] = w;
		a[y][x] = w;
	}
	for(int i = 0; i < n; i++){
		dis[i] = inf;
		pre[i] = -1;
		sum[i] = 0;
		vis[i] = false;
		cnt[i] = 0;
	}
	
	dijkstra(s);
    
	display(d); 
	
}

L2-002 链表去重(链表)

(1)数组模拟实现静态链表
(2)输出格式的控制

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 +5;
int a[N];
int vis[N];
int res[N];
int idx;
struct node{
	int key,next;
}; 
int main(){
	node no[N],res[N];
	int next,n;
	cin >> next >>n;
	memset(vis,0,sizeof(vis));
	int id,key,ne;
	for(int i = 1; i <= n; i++){
		cin >> id;
		cin >> no[id].key >> no[id].next;
	}
	int j = 0, k = 0;
	for(int i = next; i != -1; i = no[i].next){
		if(vis[abs(no[i].key)] == 0){
			vis[abs(no[i].key)] = 1;
			k = i;	
		} else{
			res[j].key = no[i].key;
			res[j].next = i;  //存储的是自己本身的地址(输出的时候先输出自身的next,在输入下一个点的next即可)
			no[k].next = no[i].next;
			j++;
		}
	}
	for(int i = next; i != -1; i = no[i].next){
		if(no[i].next != -1){
			printf("%05d %d %05d\n", i, no[i].key,no[i].next);
		}
        else
        {
            printf("%05d %d -1\n", i, no[i].key);
        }
		
	}	
	 for (int i = 0; i < j; i++)
    {
        if (i < j - 1)
            printf("%05d %d %05d\n", res[i].next, res[i].key, res[i + 1].next);
        else
            printf("%05d %d -1\n", res[i].next, res[i].key);
    }
}

L2-003 月饼(贪心)

贪心:优先使用单位价值最大的
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
struct info{
	double w;
	double v;
	double d;
}g[N];
bool cmp(info x1, info x2){
	return x1.d > x2.d;
}
int main(){
	int n,d;
	cin >> n >> d;
	for(int i = 1; i <= n;i ++){
		cin >> g[i].w;
	}
	for(int i = 1; i <= n;i ++){
		cin >> g[i].v;
		g[i].d = g[i].v / g[i].w;
	}
	
	sort(g+1,g + 1 + n,cmp);
	double num = 0;
	double ans = 0;
	for(int i = 1; i <= n; i++){
		if(g[i].w <= d){
			ans += g[i].v;
			d =d - g[i].w;
		}else{
			ans = ans + g[i].d * d;
			break;
		}
	}
	
	printf("%.2f",ans);
}

L2-005 集合相似度(vector+set)

STL的使用
vector()
find()顺序查找值
end()获取末尾的迭代器

#include<bits/stdc++.h>
#include <vector>
#include <set>
using namespace std;

int main(){
	int n;
	cin >> n;
	vector<set<int>>v(n + 1);
	for(int i = 1; i <= n; i++){
		int k;
		cin >> k;
		for(int j =0; j < k; j++){
			int t;
			cin >> t;
			v[i].insert(t);
		}
	}
	int m;
	cin >> m;
	for(int i = 1; i <= m; i++){
		int com = 0,x,y;
		cin >> x >> y;
		for(int it:v[x]){
			if(v[y].find(it) != v[y].end()) {
				com++;
			}
		}
		printf("%.2lf%%\n", 100.0 * com / (v[x].size() + v[y].size() - com));
	}
		
}

二叉树的建树与遍历

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> v;
struct node {
    int l;
    int r;
    int val;
}a[1000];
int b[1000];
int tot = 0;

void lfs(int x) {
    if (a[x].l == a[x].r && a[x].l == -1) {
        cout << x << ' ' << a[x].val << endl;
        return ;
    }
    
    if (a[x].l != -1) {
        lfs(a[x].l);
    }
    
    if (a[x].r != -1) {
        lfs(a[x].r);
    }
    
    return;
}


int dfs(int l,int r) {
    
    int root = ++tot;
    a[root].val = b[l];
    
    if (l == r) {
        a[root].l = a[root].r = -1;
        return root;
    }
    
    
    int sr = 0;
    //左子树
    for(int i = l + 1; i <= r; i++){
        if(b[i] >= a[root].val){
            sr = i - 1;
            break;
        }
    }
    //右子树
    int rl = sr + 1,rr = r;
    
    a[root].l = dfs(l + 1,sr);
    a[root].r = dfs(rl,rr);
    
    return root;
}
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++) {
        cin >> b[i];
    }
    int root = dfs(1,n);
    
    lfs(root);
}

L2-004 这是二叉搜索树吗?

二叉搜索树
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> v;
struct node {
    int l;
    int r;
    int val;
}a[1010];
int b[1010];
int tol = 0;

int build(int l,int r){
	
//	cout << l << " " << r << endl;
	int root = ++tol;
	a[root].val = b[l];
	
	if(l == r){
		a[root].l = a[root].r = -1;
		return root;		
	}

	int i = l + 1,lr = l + 1;
	for(i = l + 1; i <= r; i++){
		if(b[i] >= a[root].val){
			break;
		}
	}
	lr = i - 1;
	for(; i <= r; i++){
		if(b[i] < a[root].val){
			break;
		}
	}
	i --; 
	if(i != r){
		cout << "NO";
		exit(0);
	}
	if (l + 1 > lr) {
		a[root].l = -1;
	} else {
		a[root].l = build(l+1,lr);
	}
	
	if (lr + 1> r) {
		a[root].r = -1;
	} else {
		a[root].r = build(lr+1,r);
	}
	
	return root;
}

int rbuild(int l,int r){
	int root = ++tol;
	a[root].val = b[l];
	
	if(l == r){
		a[root].l = a[root].r = -1;
		return root;		
	}

	int i = l + 1,lr = l + 1;
	for(i = l + 1; i <= r; i++){
		if(b[i] < a[root].val){
			break;
		}
	}
	lr = i - 1;
	for(; i <= r; i++){
		if(b[i] >= a[root].val){
			break;
		}
	}

	i --;
	if(i != r){
		cout << "NO" << endl;
		exit(0);
	}
	if (l + 1 > lr) {
		a[root].l = -1;
	} else {
		a[root].l = rbuild(l+1,lr);
	}
	
	if (lr + 1> r) {
		a[root].r = -1;
	} else {
		a[root].r = rbuild(lr+1,r);
	}
	
	
	return root;
}
void postorder(int root){
	if(a[root].l == a[root].r && a[root].l == -1){
		v.push_back(a[root].val);
		return;
	}
	if(a[root].l != -1){
		postorder(a[root].l);
	}
	if(a[root].r != -1){
		postorder(a[root].r);
	}
	v.push_back(a[root].val);
}

int main(){
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> b[i];
	}
	int root = 0;
	if(b[2] >= b[1]){
		root = rbuild(1,n);
	}else{
		root = build(1,n);
	}
	postorder(root);
	
	cout << "YES" << endl;
	
	for(int i = 0; i < v.size() - 1; i ++){
		cout << v[i] << " ";
	}
	cout << v[v.size() - 1];
}

看了别人代码简洁易懂(代码引自
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define endl "\n"
#define PII pair<int,int>
#define INF 0x3f3f3f3f

const int N = 1e5+10;
int a[N],n;

vector<int> ans;

void dfs1(int root,int tail){
	if(root > tail) return;
	int l = root + 1,r = tail;
	while(a[l] < a[root] && l <= tail) l++;
	while(a[r] >= a[root] && r > root) r--;
	if(l - r != 1) return;//因为要刚好越过分界线
	dfs1(root+1,r);//向左子树递归
	dfs1(l,tail);//向右子树递归
	ans.push_back(a[root]);//将当前的父节点放入答案
	//如果我们发现是一个二叉搜索树那么ans存的就是后根遍历的结果,
	//因为是递归左右子树后才放入ans中的,下面同理
}

void dfs2(int root,int tail){
	if(root > tail) return;
	int l = root + 1,r = tail;
	while(a[l] >= a[root] && l <= tail) l++;
	while(a[r] < a[root] && r > root) r--;
	if(l - r != 1) return;
	dfs2(root+1,r);
	dfs2(l,tail);
	ans.push_back(a[root]);
}

int main()
{
	cin>>n;
	for(int i = 0;i < n; ++i) cin>>a[i];
	
	dfs1(0,n-1);
	if(ans.size() != n){
		ans.clear();
		dfs2(0,n-1);
	}
	if(ans.size() == n) {
		cout<<"YES"<<endl;
		for(int i = 0;i < n; ++i) 
			cout<<ans[i]<<" \n"[i == n-1];
	} else {
		cout<<"NO"<<endl;
	}

	return 0;
}

L2-006 树的遍历(🌳的中序/后序/层序遍历👍)

在这里插入图片描述
🌳的遍历:
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
层序遍历:按照层次进行遍历
思路:首先通过给定的后序遍历序列和中序遍历序列建🌳,后序遍历可以确定根节点,中序遍历可以划分左右子树。然后从根节点进行bfs,求出层序遍历的结果并存到vector中,遍历输出即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 40;
int n;
struct node{
    int l,r;
}t[N*4];
int post[N],mid[N];

int build(int la,int ra,int lb,int rb){
    if(la > ra || lb > rb){
        return 0;
    }
    int root = post[rb];
//     cout << root <<" ";
    int p = la;
    while(mid[p] != root){
        p++;
    }
    int len = p - la;
    t[root].l = build(la,p-1,lb,lb+len-1);
    t[root].r = build(p+1,ra,lb+len,rb - 1);
//     cout << root <<" ";
    return root;
    
}

void bfs(int root){
    vector<int> vec;
    queue<int> q;
    q.push(root);
    while(!q.empty()){
        int ret = q.front();
        q.pop();
        if(ret == 0){
            break;
        }
        vec.push_back(ret);
        if(t[ret].l != 0){
            q.push(t[ret].l);
        }
        if(t[ret].r != 0){
            q.push(t[ret].r);
        }
        
    }
    int level = vec.size();
    for(int i = 0; i < level - 1; i ++){
        cout << vec[i] << " ";
    }
    cout << vec[level - 1] << endl;
}

int main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> post[i];
    }
    for(int i = 1; i <= n; i++){
        cin >> mid[i];
    }
    build(1,n,1,n);
    bfs(post[n]);
    
}

L2-011 玩转二叉树(中序+前序+层序)

在这里插入图片描述
思路:其实并不用真的交换左右,只需要层序的时候,先存右子树再存左子树即可
注意判断下标起始,和递归结束条件

#include<bits/stdc++.h>
using namespace std;
const int N = 40;
struct node{
    int l, r;
}t[N*4];
queue<int> q;
int pre[N],mid[N];
int a[N];
int n;
void bfs(){
    int tot = 0;
    q.push(pre[1]);
    while(!q.empty()){
        int root = q.front();
        if(tot != n -1){
            printf("%d ",q.front()); 
        }else printf("%d",q.front());
        tot++;
        q.pop();
        
        if(t[root].r != 0){
            q.push(t[root].r);
        }
        if(t[root].l != 0){
            q.push(t[root].l);
        }
    }
}

int build(int la,int ra,int lb,int rb){
	if(la > ra || lb > rb){
        return 0;
    }
    int root = pre[la];
    int p = lb;
    while(mid[p] != root){
        p++;
    }
    int len = p - lb;
    t[root].l = build(la + 1,la + len,lb,p - 1);
    t[root].r = build(la + len + 1,ra,p + 1,rb);
    
    return root;
}
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> mid[i];
    }
    for(int i = 1; i <= n; i++){
        cin >> pre[i];
    }
    build(1,n,1,n);
    bfs();
}

L2-007 家庭房产(并查集)

细节比较多

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 101000;
int fa[N]; //记录父亲
int sz[N];  //记录家庭人数(并查集大小)
int tol[N];//记录家庭总人数
int sum[N];//记录家庭面积

struct node{
	int id,sz;
	double aver,area;
}p[1010];//用于对答案排序
int tot = 0; 
int n;
//寻找祖先,本题由于有些点有可能没出现过,所以不能将所有点初始化为自己的父亲
int find(int x){
	if(fa[x] == -1){  //第一次出现
		sz[x] = 1;//必须初始化,自己一个人大小为1
		return fa[x] = x;
	}
	
	if(fa[x] == x){
		return x; 
	}
	return fa[x] = find(fa[x]);
}
bool cmp (node x, node y) {
	if (abs(x.area - y.area) < 1e-6) {
		return x.id < y.id;
	}  else {
		return x.area > y.area;
	}
	
}
void merge(int x,int y){
	int fa_x = find(x);
	int fa_y = find(y);
	if(fa_x != fa_y){
	//将编号小的作为家庭的祖先
		if(fa_x < fa_y){
			fa[fa_y] = fa_x;
			sz[fa_x] += sz[fa_y];
			tol[fa_x] += tol[fa_y];
			sum[fa_x] += sum[fa_y];
		}else{
			fa[fa_x] = fa_y;
			sz[fa_y] += sz[fa_x];
			tol[fa_y] += tol[fa_x];
			sum[fa_y] += sum[fa_x];
		}
	}
}

void init() {
//初始化,不同于普通的并查集
	for (int i = 0; i <= 10000; i ++) {
		fa[i] = -1;
	}
}

signed main(){
	init();
	cin >> n;
	for(int i = 1; i <= n; i++){
		int id,fa,ma,k;
		cin >> id >> fa >> ma >> k;
//		find(id);
		if(fa != -1){
			merge(fa,id);
		}
		if(ma != -1){
			merge(ma,id);
		}
		for(int j = 1; j <= k; j++){
			int x;
			cin >> x;
			merge(id,x);
		}
		int num,are;
		cin >> num >> are;
		int pre = find(id);
		tol[pre] += num;
		sum[pre] += are;
	}
	
	for(int i = 0; i <= 100001; i++){
		if(fa[i] == i){
			++tot;
			p[tot].id = i;
			p[tot].sz = sz[i];
			p[tot].area = (double)sum[i] / (double)sz[i];
			p[tot].aver = (double)tol[i] / (double)sz[i];
		}
	}	
	sort(p + 1, p + 1 + tot, cmp);
	printf("%lld", tot);
	if (tot != 0) {
		printf("\n");
	}
	for (int i = 1; i <= tot; i ++) {
		printf("%04lld %lld %.3lf %.3lf", p[i].id, p[i].sz, p[i].aver, p[i].area);
		if (i != tot) {
			printf("\n");
		}
	}
} 

L2-008 最长对称子串(区间DP)

在这里插入图片描述

法1:暴力
只能想到暴力做法,直接枚举起点和长度即可
注意:cin不能读取空格,所以此题我们需要用getline(cin,str);来读取字符串

#include<bits/stdc++.h>
using namespace std;
bool check(string s){
	string str2 = s;
	reverse(str2.begin(),str2.end());
	if(s == str2){
		return true;
	}
	return false;
}
int main(){
	string str;
    getline(cin, str);
	int ans = 0;
	for(int i = 0; i < str.length(); i++){
		for(int len = 1; len <= str.length() - i; len++){
			string s = str.substr(i,len);//str.substr(起点,长度);
			if(check(s)){
				ans = max(len,ans);//此处需要注意,需要取最大值,不一定最后一个是最长的
			}
		}
	}
	cout << ans;
} 

法2:区间dp(👍👍👍)
太菜了,想不出来
很明显,长度为1的字符串肯定是回文串
f[i][j]表示从i开始到j的最长对称子串,状态转移的条件是中间是回文串,并且新添加进来的两个端点相等。

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N][N];
int main(){
	string str;
	getline(cin,str);
	int ans = 1;//此处需要注意,初始化为1,不是0
	for(int len = 1; len <= str.length(); len++){
		for(int i = 0; i < str.length(); i++){
			int j = i + len - 1;
			if(j >= str.length()){
				continue;
			}
			if(i == j){
				f[i][j] = 1;
				continue;
			}
			if(str[i] == str[j] && f[i+1][j-1] == j - i -1){
				f[i][j] = f[i + 1][j - 1] + 2;
			}
			ans = max(ans,f[i][j]);
		}
	}
	cout << ans;
} 

L2-009 抢红包(模拟)

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
struct info{
	int id,num;
	double money;
}p[10100];
bool cmp(info o1, info o2){
	if(o1.money != o2.money){
		return o1.money > o2.money;
	}else if(o1.num != o2.num){
		return o1.num > o2.num;
	}else{
		return o1.id < o2.id;
	}
}
int n;
int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
        p[i].id = i;
		int k; cin >> k;
		for(int j = 1; j <= k; j++){
			int id,num;
			cin >> id >> num;
			p[i].money -= num;
			p[id].num ++;
			p[id].money += num;
		}
	}
	
	sort(p + 1,p + 1 + n, cmp);
	for(int i =1 ; i <= n; i++){
		p[i].money = p[i].money / 100;
	}
	for(int i = 1; i <= n; i++){
		printf("%d %.2f",p[i].id,p[i].money);
		if(i != n){
			printf("\n");
		}
	}
	
	
	
} 

L2-010 排座位(并查集)

在这里插入图片描述思路:并查集可以维护朋友关系,刚开始以为是反集,没注意读题显然是不行的,他明确说明了敌人的敌人。
这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int enemy[N][N];
int fa[N*2];
int n,m,k;
void init(){
    for(int i = 1; i <= 2*n; i++){
        fa[i] = i;
    }
}

int find(int x){
    if(x == fa[x]){
        return x;
    }
    return fa[x] = find(fa[x]);
}
void merge(int x,int y){
    int fx = find(x);
    int fy = find(y);
    if(fx != fy){
        fa[fy] = fx;
    }
}
int main(){
    cin >> n >> m >> k;
    init();
    for(int i = 1; i <= m; i++){
        int x,y,r;
        cin >> x >> y >> r;
        if(r == 1){
            merge(x,y);
        }
        //敌人
        if(r == -1){
//             merge(x,y+n);
//             merge(y,x+n);
            enemy[x][y] = 1;
            enemy[y][x] = 1;
        }
    }
    for(int i = 1; i<= k; i++){
        int x,y;
        cin >> x >> y;
        if(find(x) == find(y) && find(x) && enemy[x][y] == 0){
            cout << "No problem" << endl;
        }
        if(find(x) == find(y) && enemy[x][y] == 1){
            cout << "OK but..." << endl;
        }
        if(find(x) != find(y) && enemy[x][y] == 0){
            cout <<"OK"<< endl;
        }
        if(find(x) != find(y) && enemy[x][y] == 1){
            cout <<"No way"  << endl;
        }
    }
    
}

L2-012 关于堆的判断(小根堆/字符串处理技巧)

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N];
int n,m;
int find(int x){
	int p = 1;
	for(int i = 1; i <= n; i++){
		if(a[i] == x){
			return i;
		}
	}
}
int main(){
    cin >> n >> m;
    for(int i = 1;i <= n; i++){ //边读入边调整建立小根堆 
    	cin >> a[i];
    	int k = i;
    	while(k > 1 && a[k] < a[k/2]){
    		swap(a[k],a[k/2]);
    		k /= 2;
		}
	}
	while(m--){
		int num;
		cin >> num;
		string s1;
		cin >> s1;
		if(s1=="is"){
			string s2;
			cin >> s2;
			if(s2 == "the"){
				string s3;
				cin >> s3;
				if(s3 == "root"){
					if(a[1] == num){
						cout << "T" << endl;
					}else{
						cout << "F" << endl;
					}
				}else{
					string s4; int x;
					cin >> s4 >> x;
					if(find(num) == find(x)/2){
						cout << "T" << endl;
					}else{
						cout << "F" << endl;
					}
				}
			}else{
				string s3,s4;int x;
				cin >> s3 >> s4 >> x;
				if(find(num)/2 == find(x)){
					cout << "T" << endl;
				}else{
					cout << "F" << endl;
				}
			}
		}else{
			int x2;string s2,s3;
			cin >> x2 >> s2 >> s3;
			if(find(x2)/2 == find(num)/2){
				cout << "T" << endl;
			}else{
				cout << "F" << endl;
			}
		}
	}
	
	
}

L2-013 红色警报(多次使用并查集)

在这里插入图片描述

输入样例:
5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3
输出样例:
City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
bool vis[N];
int fa[N];
int a[N];
int n,m,tot;
struct info{
	int x,y;
}r[5010];
void init(){
	for(int i = 0; i < n; i++){
		fa[i] = i;
	}
}
int find(int x){
	if(fa[x] == x){
		return x;
	}
	return fa[x] = find(fa[x]);
}
void merge(int x,int y){
	int fx = find(x);
	int fy = find(y);
	if(fx != fy){
		fa[fy] = fx;
	}
}
int main(){
	cin >> n >> m;
	init();
	for(int i = 1; i <= m; i++){
		int x,y;
		cin >> x >> y;
		r[i].x = x; r[i].y = y;
		merge(x,y);
	}
	for(int i = 0; i < n; i++){
		if(fa[i] == i){
			tot++;
		}
	}
	int k;
	cin >> k;
	for(int i = 1; i <= k; i++){
		int id;
		cin >> id;
		vis[id] = true;
		init();
		int cnt = 0;
		for(int j = 1; j <= m; j++){
			if(!vis[r[j].x] && !vis[r[j].y]){
				merge(r[j].x,r[j].y);
			}
		}
		for(int i = 0; i < n; i++){
			if(fa[i] == i && !vis[i]){
				cnt++;
			}
		}
		if(cnt > tot){
			printf("Red Alert: City %d is lost!",id);
		}else{
			printf("City %d is lost.",id);
		}
		if(i!=k) cout<<endl;
		if(i==n) cout<<endl<<"Game Over.";
		tot = cnt;//更新 
	}
}

L2-014 列车调度(二分答案)

在这里插入图片描述
刚开始竟然没看出可以二分,直接暴力模拟的,显然会T

#include<bits/stdc++.h>
using namespace std;
const int N = 112000;
int tail[N];
int n,m,tot;

int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		int x;
		cin >> x;
        bool ok = false;
		for(int j = 1; j <= tot; j++){
			if(x < tail[j]){
// 				cout << x << " " << tail[j];
				tail[j] = x;
                ok = true;
				break;
			}
		}
		if(ok == false){
            tail[++tot] = x;
        }
	}
	cout << tot;
} 

二分答案
很明显,我们每次需要再加一条平行道的时候此车道的最小值肯定比前面的大,所以是单调递减的,我们只需看看能否再已有有的车道中找一条大于当前值的(第一个大于当前值的),如果存在就更新当前车道最小值,如果不存在就再开一条。

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int tail[N];
int n,m,tot;

int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		int x;
		cin >> x;
//		for(int j = 1; j <= tot; j++){
//			if(x < tail[j]){
//				cout << x << " " << tail[j];
//				tail[j] = x;
//				break;
//			}
//		}

		int l = 1, r = tot, res = -1;
		while(l <= r){
			int mid = (l + r) >> 1;
			if(tail[mid] > x){
				res = mid;
				r = mid - 1;
			}else{
				l = mid + 1;
			}
		}
		if(res == -1){
			tail[++tot] = x;
		}else{
			tail[res] = x;
		}
//		tail[++tot] = x;
	}
	cout << tot;
} 

L2-015 互评成绩(排序)

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int n,m,tot,k;

struct node{
	int id;
	int mark[11];
	int maxn = -1,minn = 110;
	int sum;
	double aver;
}p[10005];
bool cmp(node o1,node o2){
	return o1.aver < o2.aver;
} 
int main(){
	cin >> n >> k >> m;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= k; j++){
			cin >> p[i].mark[j];
			p[i].maxn = max(p[i].maxn,p[i].mark[j]);
			p[i].minn = min(p[i].minn,p[i].mark[j]);
			p[i].sum += p[i].mark[j];
		}
		p[i].aver = (p[i].sum - p[i].maxn - p[i].minn) / ((double)k - 2);
	}
	sort(p+1,p+1+n,cmp);
	for(int i = n - m + 1; i <= n; i++){
		printf("%.3lf",p[i].aver);
		if(i != n){
			printf(" ");
		}
	}
}

L2-017 人以群分

在这里插入图片描述

思路:题目与中说了两个人数尽可能接近,所以偶数的时候均分即可,奇数的时候多分给外向的一个。真的服了自己课,开数组的时候少开了一个0,debug了半年。😶

#include<bits/stdc++.h>
using namespace std;
const int N = 100100;
int n,m,tot,k;
int a[N];
int n1,n2;
long long ans1,ans2,ans;
int main(){
	cin >> n;
	for(int i = 1;i <= n; i++){
		cin  >> a[i];
	}
	sort(a + 1, a + 1 + n);
	if(n % 2 == 0){
		for(int i = 1; i <= n; i++){
			if(i <= n/2){
				ans1 += a[i];
			}else{
				ans2 += a[i]; 
			}
		}
		cout << "Outgoing #: " << n/2 << endl;
		cout << "Introverted #: " << n/2 << endl;
		cout << "Diff = " << ans2 - ans1;
		 
	}else{
		int mid = n/2 + 1;
		for(int i = 1; i < mid; i++){
			ans1 = ans1 + a[i];
		}
		for(int i = mid; i <= n; i++){
			ans2 = ans2 + a[i];
		}
		cout << "Outgoing #: " << n/2 + 1 << endl;
		cout << "Introverted #: " << n/2 << endl;
		cout << "Diff = " << ans2 - ans1;
	}
}

L2-016 愿天下有情人都是失散多年的兄妹(❗❗dfs)

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct node{
	char sex;
	int f_id;
	int m_id;
}p[N];
bool com = false;
void init(){
	for(int i = 0; i < N;i++){
		p[i].f_id = -1;
		p[i].m_id = -1;
	}
}

void dfs(int f_id,int m_id,int gap){
	if(f_id == -1 || m_id == -1){
		return;
	}
	if(gap >= 5){
		return;
	}
	if(f_id == m_id){
		com = true;
	}
	//双方父母
	dfs(p[f_id].f_id,p[m_id].f_id,gap+1);
	dfs(p[f_id].m_id,p[m_id].m_id,gap+1);
	dfs(p[f_id].m_id,p[m_id].f_id,gap+1);
	dfs(p[f_id].f_id,p[m_id].m_id,gap+1);
	
}
int main(){
	init();
	int n,id;
	cin >> n;
	for(int i = 0; i < n; i++){
		cin >> id;
		cin >> p[id].sex >> p[id].f_id >> p[id].m_id;
		if(p[id].f_id != -1){
			p[p[id].f_id].sex = 'M';
		}
		if(p[id].m_id != -1){
			p[p[id].m_id].sex = 'F'; 
		}
	}
	int k;
	cin >> k;
	int x1, x2;
	for(int i = 0; i < k; i++){
		com = false;
		cin >> x1 >> x2;
		if(p[x1].sex == p[x2].sex){
			cout << "Never Mind" << endl;
		}else{
			dfs(x1,x2,0);
			if(!com){
				cout << "Yes" << endl;
			}else{
				cout << "No" << endl;
			}
		}
	}
	
	
}

L2-019 悄悄关注(map/字符串数组排序)

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 100100;
vector<int> kids[N];
double val[N],sum;
int v[N];
int n;
double z,r;

void dfs(int id,double w){
	if(val[id] != 0){ //说明是得道者
		sum = sum + w * val[id]; 
	}else{
		for(int i = 0; i < kids[id].size(); i++){
			dfs(kids[id][i],w*r);
		}
	}
}
int main(){
	int m,k;
	cin >> n >> z >> r;
//	scanf("%d %lf %lf",&n,&z,&r);
	r = (100 - r)/100;
	for(int i = 0; i < n; i++){
//		scanf("%d",&k);
		cin >> k;
		if(k == 0){
//			scanf("%lf",&val[i]);
			cin >> val[i];
		}else{
			for(int j = 1; j <= k; j++){
				int x; 
//				scanf("%d",&x);
				cin >> x;
				kids[i].push_back(x);
			}
		}
	}
	dfs(0,z);
	
//	printf("%d\n",(int)sum);
	cout << (int)sum; 
}

L2-020 功夫传人(dfs+vector)

在这里插入图片描述

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 100100;
vector<int> kids[N];
double val[N],sum;
int v[N];
int n;
double z,r;

void dfs(int id,double w){
	if(val[id] != 0){ //说明是得道者
		sum = sum + w * val[id]; 
	}else{
		for(int i = 0; i < kids[id].size(); i++){
			dfs(kids[id][i],w*r);
		}
	}
}
int main(){
	int m,k;
	cin >> n >> z >> r;
	r = (100 - r)/100;
	for(int i = 0; i < n; i++){
		cin >> k;
		if(k == 0){
			cin >> val[i];
		}else{
			for(int j = 1; j <= k; j++){
				int x; 
				cin >> x;
				kids[i].push_back(x);
			}
		}
	}
	dfs(0,z);
	cout << (int)sum; 
}

L2-021 点赞狂魔(set+结构体排序)在这里插入图片描述

#include<bits/stdc++.h>
#define long long ll
using namespace std;
const int N = 1010;
map<int, int> mp;
set<int> st; 
struct node{
	string name;
	int num;
	int tol;
}p[N];
bool cmp(node o1,node o2){
	if(o1.num != o2.num){
		return o1.num > o2.num;
	}else{
		return o1.tol < o2.tol;
	}
}
int n;
signed main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		mp.clear();
		st.clear();
		string str;int cnt;
		cin >> str >> cnt;
		p[i].name = str;
		p[i].tol = cnt;
		int count = 0;
		for(int i = 1; i <= cnt; i++){
			int x;
			cin >> x;
			st.insert(x);
//			if(mp[x] != 1){
//				mp[x] = 1;
//				++count;
//			}
		}
		p[i].num = st.size();
	}
	sort(p+1,p+1+n,cmp);
	int i = 1;
	for(;i <= min(3,n); i++){
		cout << p[i].name;
		if(i != 3){
			cout << " ";
		}
	}
	for(; i <= 3; i++){
		cout << "-";
		if(i != 3){
			cout << " ";
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

释怀°Believe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值