zoukankan      html  css  js  c++  java
  • BZOJ 1934洛谷2057善意的投票题解

    题目链接

    BZ链接

    又是一道玄学的网络流题

    我们这样建图:

    对于同意观点1的原点向其连边,对于同一观点2点向汇点连边

    然后如果两个人是朋友,就连一条双向边。

    为什么这样是对的呢?

    对于一个人来说,他要么放弃自己的观点,就是断掉自己和原点或汇点的边

    或者说他放弃他的朋友(太表面了)断掉和他朋友相连的边

    最后要使原点和汇点不连通(因为一个人不可能同意两个观点),所以我们要求的就是一个最小割

    跑最大流的板子就好了

    # include<iostream>
    # include<cstdio>
    # include<algorithm>
    # include<cstring>
    # include<cmath>
    # include<queue>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int mn = 310;
    int head[mn],edge_max=1;
    struct edge{int to,next,flow;
    };
    edge e[mn*mn*2];
    int n,m;
    void add_edge(int x,int y,int z)
    {
        e[++edge_max].to=y;
        e[edge_max].next=head[x];
        e[edge_max].flow=z;
        head[x]=edge_max;
    } 
    void add(int x,int y,int z)
    {
       add_edge(x,y,z);
       add_edge(y,x,0);
    }
    queue<int> q; 
    int deep[mn];
    bool bfs(int x,int y)
    {
        memset(deep,0,sizeof(deep));
        q.push(x);
        deep[x]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=e[i].next)
            {
                if(e[i].flow>0 && deep[e[i].to]==0)
                {
                    deep[e[i].to]=deep[u]+1;
                    q.push(e[i].to);
                }
            }
        }
        return deep[y]!=0;
    }
    int dfs(int x,int cost,int y)
    {
        if(x==y) return cost;
        for(int i=head[x];i;i=e[i].next)
        {
            if(deep[e[i].to]==deep[x]+1 && e[i].flow>0)
            {
                int di=dfs(e[i].to,min(cost,e[i].flow),y);
                if(di>0)
                {
                    e[i].flow-=di;
                    e[i^1].flow+=di;
                    return di;
                }
            }
        }
        return 0;
    }
    int dinic(int x,int y)
    {
        int ans=0;
        while(bfs(x,y))
        {
        //    printf("ssss
    ");
            while(int k=dfs(x,inf,y))
              ans+=k;
        //    printf("%d
    ",ans);
        }
        return ans;
    }
    int main()
    {
        int st,en,x,y;
        scanf("%d%d",&n,&m);
        st=n+1,en=n+2;
        for(int i=1;i<=n;i++)
        {
           scanf("%d",&x);
           if(x) {
           add(st,i,1);
           //printf("%d %d
    ",st,i);
           }
           else add(i,en,1);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y,1),add(y,x,1);
        }
        printf("%d",dinic(st,en));
        return 0;
    }
  • 相关阅读:
    firefox 使用过程
    如何在Ubuntu 18.04中安装VMware Workstation Player
    pycharm 设置
    matplotlib函数理解
    Linux:从入门到放弃
    Pycharm 项目无法导入自己写的模块(问题记录贴)
    代数之管见(孟道骥)第二讲:漫谈数学学习
    numpy学习总结(重点讲解索引方式)
    ubuntu中vi下删除键和上下左右键的异常解决
    Docker使用问题记录贴
  • 原文地址:https://www.cnblogs.com/logeadd/p/9347153.html
Copyright © 2011-2022 走看看