zoukankan      html  css  js  c++  java
  • 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!
    ",--q);
    		else printf("City %d is lost.
    ",--q);
    	}
    	if(k == n)printf("Game Over.
    ");
    	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
    ");
    		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
    ");
    				return;
    			}
    		}
    		if(now.ma != -1)
    		{
    			a[now.ma].level = now.level + 1;
    			wom.push(a[now.ma]);
    			if(vis[now.fa] == 1)
    			{
    				printf("No
    ");
    				return;
    			}
    		}
    	}
    	printf("Yes
    ");
    }	
    
    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;
    }
    
  • 相关阅读:
    (转) mysql的分区技术 .
    (转) MySQL中索引的限制
    单键索引还是组合索引
    什么是挂载?mount的用处在哪?
    java中的try-catch-finally中的return的执行顺序
    eclipse中spring配置文件的自动提示和namespace的添加
    try catch 语句中有return 的各类情况
    IOC与DI的理解
    对已经存在的没有唯一标识的表添加一个自增的id字段(利用序列sequence)操作过程
    mysql5.7导出数据提示--secure-file-priv选项问题的解决方法
  • 原文地址:https://www.cnblogs.com/wlw-x/p/13238054.html
Copyright © 2011-2022 走看看