UVAlive5135_Mining Your Own Business

好题。给一个无向图,求最少染黑多少个点后,使得任意删除一个点,每一个点都有与至少一个黑点联通。

一开始的确不知道做。看白书,对于一个联通分量,如果它有两个或以上的割点,那么这个分量中间的任何一个点都是不需要染色的。如果这个联通分量恰好有一个割点,那么这个分量需要对其中任何一个非割点染色,如果分量没有割点,那么任意取两个染色即可。

理解也不难,因为最多只是删除一个点,所以假如删除的不是割点,分量里面是绝对联通的,同时还可以通过割点对外面进行联通,如果删除的是割点,那么外面的与里面的不联通,那么这时就需要里面至少有一个黑点了。如果有两个割点,显然,无论你去掉哪一个点,这个分量都是与外面联通的。

有了这个思路题目就简单了。

召唤代码君:

解法一:找出所有的联通分量,判断每一个连通分量的割点数,更新答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#define maxn 201000
typedef long long ll;
using namespace std;

int first[maxn],next[maxn],to[maxn],edge;//graph
vector<int> bcc[maxn];
int N,bccnum;//the bcc data
int iscut[maxn],belong[maxn],d[maxn],low[maxn],child;
int U[maxn],V[maxn],stack[maxn],top;//stack
int n,m,cas=0,T;
ll ans,tot;

void _init()
{
    ans=1,tot=0,edge=-1,child=bccnum=0,top=0;
    for (int i=1; i<=n; i++) first[i]=-1,d[i]=low[i]=iscut[i]=belong[i]=0;
}

void addedge(int uu,int vv)
{
    edge++;
    to[edge]=vv,next[edge]=first[uu],first[uu]=edge;
    edge++;
    to[edge]=uu,next[edge]=first[vv],first[vv]=edge;
}

void dfs(int cur,int fa)
{
    d[cur]=low[cur]=d[fa]+1;
    for (int i=first[cur]; i!=-1; i=next[i])
    {
        if (to[i]==fa) continue;
        if (!d[to[i]])
        {
            if (fa==0) child++;
            top++; U[top]=cur,V[top]=to[i];
            dfs(to[i],cur);
            low[cur]=min(low[cur],low[to[i]]);
            if (low[to[i]]>=d[cur])
            {
                iscut[cur]=1;
                bccnum++,bcc[bccnum].clear();
                for (;;top--)
                {
                    if (belong[U[top]]!=bccnum) belong[U[top]]=bccnum,bcc[bccnum].push_back(U[top]);
                    if (belong[V[top]]!=bccnum) belong[V[top]]=bccnum,bcc[bccnum].push_back(V[top]);
                    if (U[top]==cur && V[top]==to[i])
                    {
                        top--;
                        break;
                    }
                }
            }
        }
        else low[cur]=min(low[cur],d[to[i]]);
    }
    if (fa==0 && child==1) iscut[cur]=0;
}

int main()
{
    while (scanf("%d",&m) && (m))
    {
        n=-1;
        for (int i=1; i<=m; i++)
        {
            scanf("%d%d",&U[i],&V[i]);
            n=max(n,max(U[i],V[i]));
        }
        _init();
        for (int i=1; i<=m; i++) addedge(U[i],V[i]);
        for (int i=1; i<=n; i++)
            if (!d[i])
            {
                if (first[i]==-1)
                {
                    tot++;
                    continue;
                }
                child=0;
                dfs(i,0);
            }
        for (int i=1; i<=bccnum; i++)
        {
            int cutnum=0;
            for (unsigned j=0; j<bcc[i].size(); j++)
                if (iscut[bcc[i][j]]) cutnum++;
            if (cutnum==1)
            {
                tot++;
                ans*=bcc[i].size()-1;
            }
            else if (cutnum==0)
            {
                tot+=2;
                ll tmp=bcc[i].size();
                ans*=tmp*(tmp-1)/2;
            }
        }
        printf("Case %d: %lld %lld\n",++cas,tot,ans);
    }
    return 0;

解法二:标记所有割点,每次从非割点出发,看能走到多少非割点,而且总共与多少割点相邻,(其实也就是遍历了一遍联通分量,不过实现简单一些)。

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 200200
typedef long long ll;
using namespace std;

int first[maxn],to[maxn],next[maxn],edge;
int U[maxn],V[maxn];
int d[maxn],low[maxn],tag[maxn];
bool iscut[maxn],vis[maxn];
int n,m,tot,child,sum,cut;
ll ans;

void _init()
{
    tot=0,ans=1,edge=-1;
    for (int i=1; i<=n; i++)
        first[i]=-1,iscut[i]=vis[i]=false,tag[i]=low[i]=d[i]=0;
}

void addedge(int uu,int vv)
{
    edge++;
    to[edge]=vv,next[edge]=first[uu],first[uu]=edge;
    edge++;
    to[edge]=uu,next[edge]=first[vv],first[vv]=edge;
}

void dfs(int cur,int fa)
{
    d[cur]=low[cur]=d[fa]+1;
    for (int i=first[cur]; i!=-1; i=next[i])
    {
        if (to[i]==fa) continue;
        if (!d[to[i]])
        {
            if (fa==0) child++;
            dfs(to[i],cur);
            low[cur]=min(low[cur],low[to[i]]);
            if (low[to[i]]>=d[cur]) iscut[cur]=true;
        }
        else low[cur]=min(low[cur],d[to[i]]);
    }
    if (fa==0 && child==1) iscut[cur]=false;
}

void visit(int cur,int TAG)
{
    sum++,vis[cur]=true;
    for (int i=first[cur]; i!=-1; i=next[i])
    {
        if (iscut[to[i]] && tag[to[i]]!=TAG) cut++,tag[to[i]]=TAG;
            else if (!iscut[to[i]] && !vis[to[i]]) visit(to[i],TAG);
    }
}

int main()
{
    int cas=0;
    while (scanf("%d",&m) && (m))
    {
        n=0;
        for (int i=1; i<=m; i++) scanf("%d%d",&U[i],&V[i]),n=max(n,max(U[i],V[i]));
        _init();
        for (int i=1; i<=m; i++) addedge(U[i],V[i]);

        for (int i=1; i<=n; i++)
            if (!d[i])
            {
                child=0;
                dfs(i,0);
            }
        for (int i=1; i<=n; i++)
            if (!vis[i] && !iscut[i])
            {
                cut=sum=0;
                visit(i,i);
                if (cut==0) tot+=2,ans*=(ll)sum*(sum-1)/2;
                    else if (cut==1) tot++,ans*=sum;
            }
        printf("Case %d: %d %lld\n",++cas,tot,ans);
    }
    return 0;
}

UVAlive5135_Mining Your Own Business,布布扣,bubuko.com

时间: 2024-12-19 02:44:23

UVAlive5135_Mining Your Own Business的相关文章

Skype for Business Server 2015系列(二)部署后端服务器

一.Skype for Business Server 2015后端SQL数据库安装 本次我们部署的是企业版的SFB,需要SQL数据库的支持,我们这次选用SQL 2014 SP1. SQL安装需要.Net Framework 3.5的支持,因此开始之前先添加.net 3.5功能. 在服务器配置管理器中添加,Windows Server 2012默认安装了net4.5,要安装3.5建议首先插入Windows Server 2012光盘,然后安装中指定光盘的%CD-Rom%\Sources\SxS\

AX2012 Business Connector Error

6.0: AxCryptoClient - New encryption key created 6.0: Unable to InitializeSession. 6.0: No built-in message corresponding to message id 0. 解决方法: 1.将登录用户设为AX中的Business Connector用户. 2.将AX中的Business Connector用户添加到本地管理员组. AX2012 Business Connector Error,

Lync 项目经验-12-为某上市企业Skype for Business购买Godday证书

<要想看Lync 2013升级SFB 2015真实项目经验:请看Lync 项目经验-01-到-Lync 项目经验-10> 本系列博文: Lync 项目经验-01-共存迁移-Lync2013-TO-SFB 2015-规划01http://dynamic.blog.51cto.com/711418/1858520 Lync 项目经验-02-共存迁移-Lync2013-TO-SFB 2015-规划02http://dynamic.blog.51cto.com/711418/1859143 Lync

Lync 项目经验-11-项目总结01-某上市企业的Skype for Business规划与实施

项目介绍: 某上市企业为了实现统一沟通,将即时消息,音频会议.视频会议.电话会议.硬件视频会议.邮件.Office 365等整合到一起,来实现统一协作. 项目现状: 1. 单域单森林. 2. 域功能级别.林功能级别都使用Windows Server 2012 R2. 3. AD域为a.org. 4. Exchange Server 2013默认域使用a.com. 5. 邮件服务器使用Exchange Server 2013,包括2台客户端访问服务器.2台邮箱服务器角色. 项目需求: 1. 部署S

Skype For Business Server 2016 无法共享PPT和白板

[环境信息] Windows Server 2012 R2 (OS补丁更新到最新) Skype For Business Server 2015 CU4 [问题描述]       使用Skype 2016客户端并且将补丁更新到最新可以正常共享白板和PPT等功能,使用Lync 2013和Skype2016客户端(没有更新任何补丁)共享白板或PPT时报如下错误"当前无法连接到服务器进行演示,错误代码141"或是"由于网络问题,您无法共享笔记以及演示白板.投票-" [解决

Lync 2013就地升级到Skype for Business 2015-01

需求 在我们将服务器升级到Skype for Business 2015之前,我们当前的环境需要满足以下要求: ·        Microsoft Lync Server 2013 CU5(February 2015 update) or above ·        PowerShell RTM version (6.2.9200.0)or later ·        SQL Server 2012 SP1 or later ·        Kb2533623 Windows Serve

Lync 2013就地升级到Skype for Business 2015-02

边缘服务器 在将Lync 2013前端服务器升级成功之后,接下来升级Lync 2013边缘服务器.升级过程与升级前端非常相似. 在前端服务器上打开Topology Builder ,download the Topology右击 EdgePool 并选择 Upgrade to Skype for Business Server 2015: 在升级拓扑之后,右击左上角的Skype for Business Server选择 Publish Topology. 在拓扑升级之后,在边缘服务器上停止Ly

Skype For Business 2015实战系列11:创建并发布拓扑

Skype For Business 2015实战系列11:创建并发布拓扑 Skype For Business Server安装前需要先定义好拓扑,因为我们要在拓扑中的每台服务器上安装 Skype for Business Server 系统,必须首先创建和发布一个拓扑.发布拓扑时,拓扑信息会载入中央管理存储数据库.如果这是 Enterprise Edition 池,您将在初次发布新拓扑时创建中央管理存储数据库.如果是 Standard Edition,则需要运行部署向导中的"准备第一个 St

Skype For Business 2015实战系列12:安装前端服务器

Skype For Business 2015实战系列12:安装前端服务器 配置Front01: 打开Skype for Business Server部署向导,点击"安装或更新Skype for Business Server系统": 安装本地配置存储: 点击"运行": 点击下一步: 安装完成,点击完成: 安装或删除Skype for Business Server组建: 点击运行: 点击下一步: 安装完成,点击完成: 请求.安装或分配证书: 点击运行: 输入基本