题目描述
dzy 手上有一张n 个点m 条边的联通无向图,仙人掌是一张每条边最多在一个简单环内的联通无向图。他想求这个无向图的生成仙人掌中最多有多少条边。
但是dzy 觉得这个问题太简单了,于是他定义了“美丽的生成仙人掌”,即在一个生成仙人掌中如果满足对于任意编号为i,j(i < j) 的两点,存在一条它们之间的简单路径上面有j-i+1 个点,则这个仙人掌是美丽的。
他现在想要知道这张图的美丽的生成仙人掌中最多有多少条边,你能帮帮他吗?
题目解析
研究题目可以发现,美丽的生成仙人掌中 iii 和 i+1i+ 1i+1 中必定有一条边。所以问题变成了:我们在一条链上加上若干条边使得得到的图是仙人掌且边数量最大。
显而易见,每一条非链边对应了链上的一个区间。于是问题就变成了选出最多数量的线段使得其互不相交。
这个可以用 dp 来实现,令 F[i]为右端点最大为 i 的区间的答案。则有:
F[i]=max(F[j]+1(i和j之间存在一条边),F[i−1])F[i] =max(F[j]+ 1(i 和 j 之间存在一条边),F[i-1])F[i]=max(F[j]+1(i和j之间存在一条边),F[i−1])
对于iii和jjj之间存在一条边,可以用到贪心,只取距离最近的点连边。
代码
#include<bits/stdc++.h>
#define ll long long
#define N 100005
using namespace std;
ll x,y,t,n,m;
ll g[N],f[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
if(x>y) swap(x,y);
if(x<y-1&&g[y]<x)
g[y]=x;
}
for(int i=1;i<=n;i++)
if(g[i]>0)
{
if(f[g[i]]+1>f[i-1]) f[i]=f[g[i]]+1;
else f[i]=f[i-1];
}
else f[i]=f[i-1];
cout<<f[n]+n-1;
}