Daliy Algorithm (tarjan, greedy, bfs )-- day 92

Nothing to fear


种一棵树最好的时间是十年前,其次是现在!

那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

2020.7.4


人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

GPLT -L2-014 - 列车调度

思路

根据题意推断题目是让我们求出一个序列具有多少个下降子序列

我们知道序列中夏季那个子序列的个数 = 序列中最长上升子序列的长度

于是我们只需要求出该序列的最长上升子序列即可,但是我们发现N的范围为$$10^5$,普通的求最长上升子序列的方法一定会超出时间限制,于是我们改变一种方法

我们定义一个数组 f[i] : 存储长度为 i 的最长上升子序列的末尾元素。

此时有两种情况:

    1. 如果当前元素大于前一个位置的末尾元素,则长度增加:f[++len] = a[i]
    1. 如果当前与不大于前一位位置的末尾元素,则其长度一定在【1,i- 1】之间我们利用二分的在前面找到一个刚好比当前元素大的元素,替换它。
  • 需要注意的是我们需要将f数组的初始值设置为INF
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <cstring>

using namespace std;

const int N = 100005;

int a[N] , n , f[N] , len;
int main()
{
	int n;
	cin >> n;
	for(int i = 1;i <= n;i ++)
	{	
		scanf("%d",&a[i]);
	}
	memset(f , 0x3f , sizeof f);
	f[1] = a[1];len = 1;
	for(int i = 2;i <= n;i ++)
	{
		if(a[i] > f[len])f[++len] = a[i];
		else{
			int l = 1, r= len;
			while(l < r)
			{
				int mid = l + r >> 1;
				if(f[mid] >= a[i])r = mid;
				else l = mid + 1;
			}
			f[l] = min(f[l] , a[i]);
		}
	}
	cout << len << endl;
	return 0;
}

GPLT - L2-013 - 红色警报

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int SIZE = 5005;
int map[SIZE][SIZE];
int dfn[SIZE] , low[SIZE];
int n , m , tot , num , root;

bool cut[SIZE];
void tarjan(int x)
{
	// 首先更新时间戳和回溯值
	dfn[x] = low[x] = ++num;
	int flag = 0; // 用于盘顶找到多少个符合条件的y
	// 枚举和 x 相连的 顶点
	for(int y = 1; y <= n; y ++)
	{
		if(map[x][y])
		{
			if(!dfn[y]) // 如果这个点还没有被访问那么立刻进行访问
			{
				tarjan(y);
				// 更新 x 点的追溯值
				// 若x是y的父节点,low[x] = min(low[x],low[y]);
				low[x] = min(low[x] , low[y]);
				// 若找到使得 dfn[x] <= low[y]的结点则flag ++ 
				// flag 用于记录这样的结点有多少个
				if(low[y] >= dfn[x])
				{
					flag++;
					// 若 点 x不是根节点且存在两个这样的结点则其为割点
					if(x != root || flag > 1)
					{
						cut[x] = true;
					}
				}
			}
			// 此时 无向边(x , y)不是搜索树上的边
			// 更新 low[x] = min(low[x] , dfn[y]);
			else low[x] = min(low[x] , dfn[y]);
		}
	}
}

void init()
{
	num = 0;
	memset(dfn , 0 , sizeof dfn);
	memset(low , 0 , sizeof low);
	memset(cut , 0 , sizeof cut);
	for(int i = 1;i <= n ;i ++)
	{
		if(!dfn[i])root = i , tarjan(i);
	}
}
int main()
{
	int x , y;
	cin >> n >> m;
	for(int i = 1;i <= m;i ++)
	{
		scanf("%d %d",&x ,&y);
		x ++ , y ++;
		if(x == y)continue;
		map[x][y] = 1; 
		map[y][x] = 1;
	}

	int k , q;
	cin >> k;
	for(int i = 0;i < k;i ++)
	{
		scanf("%d",&q);
		q++;init();
		for(int i = 1;i <= n;i ++)
		{
			map[q][i] = 0;
			map[i][q] = 0;
		}
		if(cut[q])printf("Red Alert: City %d is lost!\n",--q);
		else printf("City %d is lost.\n",--q);
	}
	if(k == n)printf("Game Over.\n");
	return 0;
}

GPLT - L2-015 - 互评成绩

排序 + 模拟

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <algorithm>

using namespace std;
const int N = 10005;
int n, k , m;

double score[N];
double ans[N];
int len = 0;
int main()
{
	cin >> n >> k >> m;
	for(int i = 0;i < n ;i ++)
	{
		for(int i = 0;i < k;i ++)
		{
			cin >> score[i];
		}
		sort(score , score + k);
		double tmp = 0;
		for(int i = 1;i < k - 1;i ++)
		{
			tmp += score[i];
		}
		ans[len++] = tmp * 1.0 / (k-2);
	}
	sort(ans , ans + n);
	for(int i = n - m;i < n;i ++)
	{
		if(i == n - m)printf("%.3f",ans[i]);
		else printf(" %.3f", ans[i]);
	}
	return 0;
}

GPLT - L2-016 愿天下有情人都是失散多年的兄妹

思路

我们根据输入的id进行向上的广度优先搜索。假设给定两个人的信息,首先从任意一个开始,进行其五代之内的祖先的搜索,在搜索的过程中用一个数组标记这些祖先已经出现。之后再让另外一个人进行对其五代之内的祖先搜索,如果搜索到相同的祖先即不可能结婚

坑点

  • 需要标注自己父母的性别,否则会出现自己长辈中同性结婚的情况
  • 需要自己筛选掉 特殊情况 0 这里将其同意标记为 -1
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

const int N = 100005;
int n , k;

struct node{
	int id = -1;
	int sex; // 1表示男性, 0 表示女性
	int fa = -1, ma = -1;
	int level;
}a[N];

bool vis[N];

void check(int x , int y)
{
	if(a[x].sex == a[y].sex)
	{
		printf("Never Mind\n");
		return;
	}
	memset(vis , 0 , sizeof vis);
	queue<node> man , wom;
	a[x].level = 1;a[y].level = 1;
	vis[x] = vis[y] = 1;
	man.push(a[x]);wom.push(a[y]);
	while(!man.empty())
	{
		node now = man.front();man.pop();
		if(now.id == -1)continue;
		if(now.level >= 5)break;
		if(now.fa != -1)
		{
			a[now.fa].level = now.level + 1; //代数
			man.push(a[now.fa]) , vis[now.fa] = 1;
		}
		if(now.ma != -1)
		{
			a[now.ma].level = now.level + 1;
			man.push(a[now.ma]) , vis[now.ma] = 1;
		}
	}
	while(!wom.empty())
	{
		node now = wom.front();wom.pop();
		if(now.id == -1)continue;
		if(now.level >= 5)break;
		if(now.fa != -1)
		{
			a[now.fa].level = now.level + 1; //代数
			wom.push(a[now.fa]);
			if(vis[now.fa] == 1)
			{
				printf("No\n");
				return;
			}
		}
		if(now.ma != -1)
		{
			a[now.ma].level = now.level + 1;
			wom.push(a[now.ma]);
			if(vis[now.fa] == 1)
			{
				printf("No\n");
				return;
			}
		}
	}
	printf("Yes\n");
}	

int main()
{
	cin >> n;
	int id , fa , ma ;char c;
	for(int i = 0;i < n;i ++)
	{
		scanf("%d %c %d %d", &id ,&c,&fa ,&ma);
		a[id].id = id;
		a[id].sex = (c == 'F' ? 0 : 1);
		a[id].fa = fa;a[id].ma = ma;
		if(fa != -1)a[fa].sex = 1;
		if(ma != -1)a[ma].sex = 0;
	}
	cin >> k;
	int man , woman;
	for(int i = 0;i < k ;i ++)
	{
		scanf("%d %d",&man , &woman);
		check(man , woman);
	}
	return 0;
}
posted @ 2020-07-05 10:39  _starsky  阅读(146)  评论(0编辑  收藏  举报