仙人掌(cactus)

时间:2023-03-09 00:01:20
仙人掌(cactus)

仙人掌(cactus)

Time Limit:1000ms Memory Limit:64MB

题目描述

LYK 在冲刺清华集训(THUSC) !于是它开始研究仙人掌,它想来和你一起分享它最近
研究的结果。

仙人掌(cactus)

如果在一个无向连通图中任意一条边至多属于一个简单环 (简单环的定义为每个点至多
经过一次) ,且不存在自环,我们称这个图为仙人掌。
LYK 觉得仙人掌还是太简单了,于是它定义了属于自己的仙人掌。
定义一张图为美妙的仙人掌, 当且仅当这张图是一个仙人掌且对于任意两个不同的点 i,j,
存在一条从 i 出发到 j 的路径,且经过的点的个数为|j-i|+1 个。
给定一张 n 个点 m 条边且没有自环的图,LYK 想知道美妙的仙人掌最多有多少条边。

数据保证整张图至少存在一个美妙的仙人掌。

输入格式(cactus.in)

第一行两个数 n,m 表示这张图的点数和边数。
接下来 m 行,每行两个数 u,v 表示存在一条连接 u,v 的无向边。

输出格式(cactus.out)

一个数表示答案

输入样例

4 6
1 2
1 3
1 4
2 3
2 4
3 4

输出样例

4

样例解释

选择边 1-2,1-3,2-3,3-4,能组成美妙的仙人掌,且不存在其它美妙仙人掌有超过 4 条
边。

数据范围

对于 20%的数据 n<=3。
对于 40%的数据 n<=5。
对于 60%的数据 n<=8。
对于 80%的数据 n<=1000。
对于 100%的数据 n<=100000 且 m<=min(200000,n*(n-1)/2)。

思路:

  仙人掌可以简化为一个线段覆盖问题

  说白了就是每个点只能被一条线段覆盖(不包括线段两边的点)

  不能被更多的线段覆盖

  所以我们可以在预处理所有的边后进行一次贪心取边

  来,上代码:

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; struct node {
int from,to;
};
struct node edge[]; int n,m,num=,pd[],jkl;
int from,to,tmp,ans=,cur=-; char ch; void qread(int &x)
{
x=,jkl=;ch=getchar();
while(ch>''||ch<''){if(ch=='-')jkl=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+(int)(ch-'');ch=getchar();}
x*=jkl;
} void edge_add(int from,int to)
{
num++;
edge[num].to=to;
edge[num].from=from;
} bool cmp1(struct node a,struct node b){return a.from>b.from;} bool cmp(struct node a,struct node b){return a.to<b.to;} int main()
{
qread(n),qread(m);
for(int i=;i<=m;i++)
{
qread(from),qread(to);
if(from>to) tmp=from,from=to,to=tmp;
//if(pd[to]==0&&from==to-1) ans++,pd[to]=1;
//else edge_add(from,to);
if(from+==to) continue;
edge_add(from,to);
}
sort(edge+,edge+num+,cmp1);
sort(edge+,edge+num+,cmp);
for(int i=;i<=num;i++)
{
if(edge[i].from>=cur)
{
cur=edge[i].to;
ans++;
}
}
cout<<ans+n-<<endl;
return ;
}