洛谷 2272 & bzoj 1093 [ZJOI2007]最大半连通子图 题解(强连通分量,思维)

该博客介绍了如何解决最大半连通子图问题,通过分析题意,将问题转化为寻找强连通分量并进行缩点。将原图转换为DAG后,问题简化为寻找最长链。利用动态规划方法求解,并在求解过程中记录相同解的数量。
摘要由CSDN通过智能技术生成

原题链接:
洛谷
bzoj

题意简述

给定一个图,点数1e5,边数1e6。定义一个“半联通”的子图为:对于任意点 ( u , v ) (u,v) (u,v),满足: u u u能到 v v v v v v能到 u u u。求最大的半联通子图点数,并求出满足像这样最大的解有多少个。

思路

(这个题是我做志愿者的时候做的。。。背着老师偷偷做题真tm爽。。。)

看起来这个“半联通”和“强连通”有点像,只不过一个是,一个是。但就是因为这个改成,就不好做了。

但是我们想一想,一个强连通分量是不是一个半联通子图?(woc我个智障想了半天才想到这一点)是的!
所以我们把强连通分量缩点即珂。由于要求最大点数,所以缩点时要维护这个分量里的点数。
然后图就变成了一个 D A G DAG DAG。在 D A G DAG DAG里就好做很多了。而且有一个明显的结论: D A G DAG DAG中的半联通子图一定是一个链。

如果你不知道为啥,看这里的解释
blog1.jpg
此时显然我们选择了两条链。但是这两个红色的点就无法到达了,两边都不能到达,所以连“半联通”也不算。所以我们只能选择一条链。

然后就变成了带权的最长链问题了。 d p dp dp即珂。
然后求个数?套路的,我们都 d p dp dp了,在能取到相同的 d p dp dp值时,用 + = += +=记录个数即珂。

代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
   
    #define N 100100
    #define MEM(x,a) memset(x,a,sizeof(x))
    #define CLS(x) memset(x,0,sizeof(x))
 
    class Graph
    {
   
        public:
            int *head;
            int EdgeCount;
            struct Edge
            {
   
                int To,Label,Next;
            }*Ed;
            int MAX;
 
            void SET(int len)
            {
   
                MAX=(len<<1)+100;
                Ed=new Edge[MAX];
                head=new int[MAX];
 
                memset(head,-1,sizeof(int)*MAX);
                memset(Ed,-1,sizeof(Edge)*MAX);
                EdgeCount=0;
            }
            void clear()
            {
   
                memset(</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值