【算法提高——第三讲(二)】图论(3)

简介: 【算法提高——第三讲(二)】图论(3)

3.11 无向图的双连通分量

3.11.1 395. 冗余路径

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
const int N=5010,M=20010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int id[N],dcc_cnt;
bool is_bridge[M];
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u,int from)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u);
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j,i);
            low[u]=min(low[u],low[j]);
            if(dfn[u]<low[j])
            {
                is_bridge[i]=is_bridge[i^1]=true;
            }
        }
        else if(i!=(from^1))
            low[u]=min(low[u],dfn[j]);
    }
    if(dfn[u]==low[u])
    {
        ++dcc_cnt;
        int y;
        do{
            y=stk.top();
            stk.pop();
            id[y]=dcc_cnt;
        }while(y!=u);
    }
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    tarjan(1,-1);
    for(int i=0;i<idx;i++)
    {
        if(is_bridge[i])
            d[id[e[i]]]++;
    }
    int cnt=0;
    for(int i=1;i<=dcc_cnt;i++)
        if(d[i]==1)
            cnt++;
    cout<<(cnt+1)/2;
    return 0;
}

3.11.2 1183. 电力

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=300010;
int n,m;
int dfn[N],low[N],timestamp;
int root,ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    int cnt=0;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
            if(low[j]>=dfn[u]) cnt++;
        }
        else low[u]=min(low[u],dfn[j]);
    }
    if(u!=root) cnt++;
    ans=max(ans,cnt);
}
int main()
{
    while(true)
    {
        cin>>n>>m;
        if(n==0&&m==0) break;
        memset(h,-1,sizeof h);
        memset(dfn,0,sizeof dfn);
        idx=timestamp=0;
        while(m--)
        {
            int a,b;
            cin>>a>>b;
            add(a,b),add(b,a);
        }
        ans=0;
        int cnt=0;
        for(root=0;root<n;root++)
        {
            if(!dfn[root])
            {
                cnt++;
                tarjan(root);
            }
        }
        cout<<ans+cnt-1<<endl;
    }
    return 0;
}

3.11.3 396. 矿场搭建

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1010,M=1010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int dcc_cnt;
vector<int> dcc[N];
bool cut[N];
int root;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++timestamp;
    stk.push(u);
    if(u==root&&h[u]==-1)
    {
        dcc_cnt++;
        dcc[dcc_cnt].push_back(u);
        return;
    }
    int cnt=0;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
            if(dfn[u]<=low[j])
            {
                cnt++;
                if(u!=root||cnt>1) cut[u]=true;
                ++dcc_cnt;
                int y;
                do{
                    y=stk.top();
                    stk.pop();
                    dcc[dcc_cnt].push_back(y);
                }while(y!=j);
                dcc[dcc_cnt].push_back(u);
            }
        }
        else low[u]=min(low[u],dfn[j]);
    }
}
int main()
{
    int T=1;
    while(true)
    {
        cin>>m;
        if(m==0) break;
        memset(h,-1,sizeof h);
        memset(dfn,0,sizeof dfn);
        memset(cut,0,sizeof cut);
        for(int i=0;i<N;i++) dcc[i].clear();
        idx=n=timestamp=dcc_cnt=0;
        while(m--)
        {
            int a,b;
            cin>>a>>b;
            add(a,b),add(b,a);
            n=max(n,a);
            n=max(n,b);
        }
        for(root=1;root<=n;root++)
        {
            if(!dfn[root])
                tarjan(root);
        }
        int res=0;
        ULL num=1;
        for(int i=1;i<=dcc_cnt;i++)
        {
            int cnt=0;
            for(int j=0;j<dcc[i].size();j++)
            {
                if(cut[dcc[i][j]])
                    cnt++;
            }
            if(cnt==0)
            {
                if(dcc[i].size()>1) res+=2,num*=dcc[i].size()*(dcc[i].size()-1)/2;
                else res++;
            }
            else if(cnt==1) res++,num*=dcc[i].size()-1;
        }
        cout<<"Case "<<T<<": "<<res<<" "<<num<<endl;
        T++;
    }
    return 0;
}

3.12 二分图

3.12.1 257. 关押罪犯

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
const int N=20010,M=200010;
int n,m;
int color[N];   //0表示未染色,1表示染白色,2表示染黑色
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int c,int mid)
{
    color[u]=c;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(w[i]<=mid) continue;
        if(color[j])
        {
            if(color[j]==c) return false;
        }
        else if(!dfs(j,3-c,mid)) return false;
    }
    return true;
}
bool check(int mid)
{
    memset(color,0,sizeof color);
    for(int i=1;i<=n;i++)
    {
        if(!color[i])
        {
            if(!dfs(i,1,mid))
                return false;
        }
    }
    return true;
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>m;
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    int l=0,r=1e9;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<r;
    return 0;
}

3.12.2 372. 棋盘覆盖

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;
int n,t;
PII match[N][N];
int g[N][N];
bool st[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool findG(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<1||a>n||b<1||b>n) continue;
        if(st[a][b]||g[a][b]) continue;
        st[a][b]=true;
        PII t=match[a][b];
        if(t.first==-1||findG(t.first,t.second))
        {
            match[a][b]=make_pair(x,y);
            return true;
        }
    }
    return false;
}
int main()
{
    cin>>n>>t;
    while(t--)
    {
        int x,y;
        cin>>x>>y;
        g[x][y]=true;
    }
    memset(match,-1,sizeof match);
    int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if((i+j)%2&&!g[i][j])
            {
                memset(st,0,sizeof st);
                if(findG(i,j)) res++;
            }
        }
    }
    cout<<res;
    return 0;
}

3.12.3 376. 机器任务

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n,m,k;
int match[N];
bool g[N][N],st[N];
bool findG(int x)
{
    for(int i=1;i<m;i++)
    {
        if(!st[i]&&g[x][i])
        {
            st[i]=true;
            if(match[i]==-1||findG(match[i]))
            {
                match[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    while(true)
    {
        cin>>n;
        if(n==0) break;
        cin>>m>>k;
        memset(g,0,sizeof g);
        memset(match,-1,sizeof match);
        while(k--)
        {
            int t,a,b;
            cin>>t>>a>>b;
            if(!a||!b) continue;
            g[a][b]=true;
        }
        int res=0;
        for(int i=1;i<n;i++)
        {
            memset(st,0,sizeof st);
            if(findG(i)) res++;
        }
        cout<<res<<endl;
    }
    return 0;
}

3.12.4 378. 骑士放置

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;
int n,m,t;
int g[N][N];
PII match[N][N];
bool st[N][N];
int dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1};
bool findG(int x,int y)
{
    for(int i=0;i<8;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<1||a>n||b<1||b>m) continue;
        if(st[a][b]||g[a][b]) continue;
        st[a][b]=true;
        PII t=match[a][b];
        if(t.first==-1||findG(t.first,t.second))
        {
            match[a][b]=make_pair(x,y);
            return true;
        }
    }
    return false;
}
int main()
{
    cin>>n>>m>>t;
    for(int i=0;i<t;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x][y]=true;
    }
    memset(match,-1,sizeof match);
    int res=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if((i+j)%2&&!g[i][j])
            {
                memset(st,0,sizeof st);
                if(findG(i,j)) res++;
            }
        }
    }
    cout<<n*m-res-t;
    return 0;
}

3.12.5 379. 捉迷藏

image.png


代码:


#include<bits/stdc++.h>
using namespace std;
const int N=210;
int n,m;
int match[N];
bool st[N],d[N][N];
bool findG(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(d[x][i]&&!st[i])
        {
            st[i]=true;
            int t=match[i];
            if(t==0||findG(t))
            {
                match[i]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        d[a][b]=true;
    }
    //求传递闭包
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j]|=d[i][k]&d[k][j];
    int res=0;
    for(int i=1;i<=n;i++)
    {
        memset(st,0,sizeof st);
        if(findG(i)) res++;
    }
    cout<<n-res;
    return 0;
}

相关文章
|
6月前
|
机器学习/深度学习 安全 算法
【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II
【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II
|
6月前
|
算法 测试技术 C++
【动态规划】【图论】【C++算法】1575统计所有可行路径
【动态规划】【图论】【C++算法】1575统计所有可行路径
|
存储 算法 索引
数据结构与算法之图论及其相关算法
图的基本介绍 线性表局限于一个直接前驱和一个直接后继的关系,树也只能有一个直接前驱也就是父节点,当我们需要表示多对多的关系时, 这里我们就用到了图。 图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。 结点也可以称为顶点。如图: 简单来说,图就是由顶点的有穷非空集合和顶点之间的边组成的集合。通常表示为:G(V,E),其中,G 表示一个图,V 表示顶点的集合,E 表示边的集合。 然后我们说说图中的一些常见概念: 节点(Vertex):图中的基本元素,用于表示某个实体。 边(Edge):连接两个节点的线段,用于表示节点之间的关系。 度(Degree):
54 0
|
6月前
|
算法 测试技术 C++
【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费
【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费
|
算法 存储 内存技术
【AcWing算法基础课】第三章 搜索与图论(2)
特点:尽可能先向纵深方向搜索。使用stack实现。所需空间O(h)(h为深度)。不具有“最短性”。
79 0
【AcWing算法基础课】第三章 搜索与图论(2)
|
5月前
|
算法 数据挖掘 定位技术
算法必备数学基础:图论方法由浅入深实践与应用
算法必备数学基础:图论方法由浅入深实践与应用
|
6月前
|
算法 C++
一题带你写出图论算法模板!!!
一题带你写出图论算法模板!!!
|
6月前
|
算法 搜索推荐 Python
Python高级数据结构——图论算法(Graph Algorithms)
Python高级数据结构——图论算法(Graph Algorithms)
155 0
|
6月前
|
算法 C++ NoSQL
|
6月前
|
存储 算法 定位技术
图论算法dijkstra dfs bfs以及动态规划
图论算法dijkstra dfs bfs以及动态规划
79 0