Daliy Algorithm (tarjan, greedy, bfs )-- day 92
Nothing to fear
种一棵树最好的时间是十年前,其次是现在!
那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~
2020.7.4
人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!
GPLT -L2-014 - 列车调度
思路:
根据题意推断题目是让我们求出一个序列具有多少个下降子序列
我们知道序列中夏季那个子序列的个数 = 序列中最长上升子序列的长度
于是我们只需要求出该序列的最长上升子序列即可,但是我们发现N的范围为$$10^5$,普通的求最长上升子序列的方法一定会超出时间限制,于是我们改变一种方法
我们定义一个数组 f[i] : 存储长度为 i 的最长上升子序列的末尾元素。
此时有两种情况:
-
- 如果当前元素大于前一个位置的末尾元素,则长度增加:f[++len] = a[i]
-
- 如果当前与不大于前一位位置的末尾元素,则其长度一定在【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;
}