zoukankan      html  css  js  c++  java
  • [10.27_P3] 简单题 (脑洞)


    Description

    dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。
    但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为i,j (i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点,则这个仙人掌是美丽的。
    他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?

    Input

    第一行两个整数n,m。接下来m 行每行两个整数ui,vi,表示这两个点之间有一条无向边。保证图中没有自环。

    Output

    仅一行一个整数表示答案。

    Sample Input

    2 1
    1 2

    Sample Output

    1

    Hint

    对于10% 的数据,n <=10。
    对于30% 的数据,n <=10^3。
    对于100% 的数据,n <=10^5,m <= 2n。

    时间限制:1S

    空间限制:256M


    题解

    这是道好题。最开始拿到题,第一反应这是道图论题。但是想了很久都想不出来该怎么搞。
    根据题意,因为数据保证有解,所以在图中必定存在一条从1 -> 2 -> ... -> n的链,最后的答案呢肯定是以此为基础的。
    我们把 1 到 n 的这条链看作是一条线段。再加边看作是用一条新的线段来覆盖。根据仙人掌图的定义,任何一条边不能同时存在于两个不同的环中。意思就是在新加的这些线段中不能有任何两条线段覆盖同一个区域。求最多的边就是求最多的线段。这不就是一个简单的线段覆盖问题么? 把所有边按右端点排序,一个贪心就好了。

    代码

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 1e5 + 5;
    int n,m;
    int vis[maxn];
    
    struct edge {
    	int l,r;
    	bool operator < (const edge &a) const {
    		return r < a.r;
    	}
    }e[maxn << 1];
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i = 0;i < m;i++) {
    		int x,y;scanf("%d%d",&x,&y);if(x > y)swap(x,y);
    		e[i] = (edge){x,y};
    	}
    	sort(e,e+m);
    	int x = 1;
    	int ans = n - 1;
    	for(int i = 0;i < m;i++) {
    		if(e[i].r == e[i].l+1&&!vis[e[i].l]) {vis[e[i].l] = 1;continue;}
    		if(e[i].l < x)continue;
    		x = e[i].r;ans++;
    	}
    	
    	printf("%d",ans);
    	return 0;
    } 
    
  • 相关阅读:
    树链剖分 (模板) 洛谷3384
    ST表 (模板) 洛谷3865
    IOI 2005 River (洛谷 3354)
    IOI 2005 River (洛谷 3354)
    poj1094 Sorting It All Out
    poj1094 Sorting It All Out
    spfa(模板)
    HAOI 2006 受欢迎的牛 (洛谷2341)
    HAOI 2006 受欢迎的牛 (洛谷2341)
    洛谷1850(NOIp2016) 换教室——期望dp
  • 原文地址:https://www.cnblogs.com/ZegWe/p/6013247.html
Copyright © 2011-2022 走看看