zoukankan      html  css  js  c++  java
  • 元旦老人与丛林

    作死写一遍没保存

    这题很经典大概吧,收获很多

    • 退流:

      网络流中如果要删去(u,v)边,则可以跑dinic(t,v,inf),dinic(u,s,inf),从而达到退流的效果,然后在把u->v的正反向边权设为0,达到删去边的效果。注意如果有最大流相关的操作,不要忘记maxflow加或减退的流量

    • 最大权闭合子图:

      如果一个图,需要选择的边对应的点都包含在图里面,则成为这个图的子图。每个点有正负权值,需要选取最大的权值的子图则成为最大权闭合子图。可以把S连向正权值的点,负权值点连向T,点与点如果有边权值为inf,显然,最小割必然在连向S或T的边中,而最小割|最大流就是问题的答案。

      对应的还有最大密度子图。

    • 对于这题:

      关键是得出 E-2*V<-2 则问题才有解这个结论,边变为点权为1,点权为-2,枚举每一个点,把该点权值变为0,依次求最大闭合子图,如果存在不满足等式条件,输出No return就完事了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=8e3+5,inf=1e9+5;
    int n,m,x,y;
    int totn,source,target;
    int dis[N],flow[N],pos[N];
    bool use[N];
    int maxflow;
    int level[N];
    struct node
    {
        int link;
        int w;
        int position;
    };
    vector<node> f[N];
    void add_edge(int x,int y,int z)
    {
        f[x].push_back((node){y, z,(int)f[y].size()});
        f[y].push_back((node){x, 0,(int)f[x].size()-1});// 获取x在y的第几条边
    }
    int dfs(int x,int flow)
    {
        int ans = 0;
        if(x==target||flow==0)
            return flow;
        for(auto &i:f[x])//结构体无法在外部改变,外面只是创建了一个临时变量(相当结构体内部变量是私有属性)
        {
            if(i.w>0&&level[i.link]==level[x]+1)// 保证边权不为0 且按照深度dfs
            {
                int d = dfs(i.link, min(flow, i.w)); // 搜索,flow是最小的所以是min
                if(d==0)
                    level[i.link] = 0;
                if(d>0)
                {
                    i.w -= d;//正向边减少
                    f[i.link][i.position].w += d;// 反向边增加
                    flow -= d;
                    ans += d;
                    if(flow==0)
                        break;
                }
            }
        }
        return ans;
    }
    bool bfs(int s,int t)
    {
        queue <int> q;
        q.push(s);
        memset(level, -1, sizeof(level));
        level[s] = 0;
        while(!q.empty())
        {
            int temp = q.front();
            q.pop();
            for(auto &i:f[temp])
            {
                if(i.w==0||level[i.link]!=-1)
                    continue;
                level[i.link] = level[temp] + 1;
                q.push(i.link);
            }
        }
        if(level[t]!=-1)
            return 1;
        return 0;
    }
    int dinic(int s,int t,int flow)
    {
        long long ans = 0;
        while(bfs(s,t))
            ans += dfs(s,flow);
        
        return ans;
    }
    int main()
    {  
        scanf("%d %d",&n,&m);
        source=0;
        target=n+m+1;
        bool flag=0;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            if(x==y)
            {
                flag=1;
                continue;
            }
            add_edge(i+n,y,inf);
            add_edge(i+n,x,inf);
        }
        if(flag==1)
        {
            printf("No
    ");
            return 0;
        }
        for(int i=1;i<=m;i++)
            add_edge(source,i+n,1);
        for(int i=1;i<=n;i++)
            add_edge(i,target,2);
    
        // for(int i=0;i<=m+n+1;i++)
        // {
        //     printf("i:%d
    ",i);
        //     for(auto j:f[i])
        //         printf("???%d %d",j.link,j.w);
        //     printf("
    ");
        // }
        int maxflow=dinic(source,target,inf);
        if(m-maxflow>0)
        {
            printf("No
    ");
            return 0;
        }
        for(int i=1;i<=n;i++)
        {
            // source=n+m+1;
            // target=n+m+1;
            // maxflow-=dinic(source,target,inf);
            source=i;
            target=0;
            maxflow-=dinic(i,0,inf);
            (f[i][int(f[i].size())-1]).w=0;
            (f[n+m+1][f[i][(int)f[i].size()-1].position]).w=0;
            source=0;
            target=n+m+1;
            maxflow+=dinic(0,n+m+1,inf);
            if(m-maxflow>0)
            {
                printf("No
    ");
                return 0;
            }
            f[i][int(f[i].size())-1].w=2;
        }
        printf("Yes
    ");
        return 0;   
    }
    /*
    5 4
    1 2
    2 3
    1 5
    2 4
    */
    
    $道路千万条,点赞第一条;阅读不规范,笔者两行泪$
  • 相关阅读:
    [公告]博客园准备建立SharePoint团队
    [公告]新增三款Skin
    又新增三款Skin
    一个不错的计数器
    [公告]新建新手区
    2005年1月16日 IT Pro 俱乐部活动纪实
    [好消息]祝成科技.微软公司.博客园联合打造IT俱乐部
    [公告]SharePoint团队正式成立
    SharePoint文档库存在问题
    [活动]2004年计算机图书评选
  • 原文地址:https://www.cnblogs.com/cherrypill/p/14328135.html
Copyright © 2011-2022 走看看