zoukankan      html  css  js  c++  java
  • 【BZOJ1934】善意的投票

    题面

    http://darkbzoj.tk/problem/1934

    $simple$的$network flow$

    每个人,两个选择,割掉S边或T边代表投赞成或反对。

    把源点连向每个人,如果他本来赞成,则边权为1,否则边权为0

    把每个人联向汇点,如果他本来反对,则边权为0,否则边权为1

    对于一对朋友,如果他们的选择相反,即他们一个连S,一个连T,构成代价,可以连一条代价为1的双向边,代表花费。

    • 最大流中,零边等价于不连。
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ri register int
    #define N 305
    #define INF 1000000007
    using namespace std;
    
    int n,m,x;
    vector<int> to,w;
    vector<int> ed[N];
    int cur[N],d[N];
    
    inline int read() {
      int f=0,ret=0; char ch=getchar();
      while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
      while (ch>='0'&&ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar();
      return f?-ret:ret;
    }
    
    void add_edge(int u,int v,int w1,int w2) {
      to.push_back(v); w.push_back(w1); ed[u].push_back(to.size()-1);
      to.push_back(u); w.push_back(w2); ed[v].push_back(to.size()-1);
    }
    
    bool bfs() {
      queue<int> q;
      memset(d,0x3f,sizeof(d));
      d[0]=0; q.push(0);
      while (!q.empty()) {
        int x=q.front(); q.pop();
        for (ri i=0,l=ed[x].size();i<l;i++) {
          int e=ed[x][i];
          if (w[e] && d[x]+1<d[to[e]]) {
            d[to[e]]=d[x]+1;
            q.push(to[e]);
          }
        }
      }
      return d[n+1]<=N;
    }
    
    int dfs(int x,int limit) {
      if (x==n+1 || !limit) return limit;
      int tot=0;
      for (ri &i=cur[x];i<ed[x].size();i++) {
        int e=ed[x][i];
        if (d[to[e]]==d[x]+1 && w[e]) {
          int f=dfs(to[e],min(limit,w[e]));
          if (!f) continue;
          w[e]-=f; w[1^e]+=f; 
          tot+=f; limit-=f;
          if (!limit) return tot;
        }
      }
      return tot;
    }
    
    int dinic() {
      int ret=0;
      while (bfs()) {
        memset(cur,0,sizeof(cur));
        ret+=dfs(0,INF);
      }
      return ret;
    }
    
    int main() {
      n=read(); m=read();
      for (ri i=1;i<=n;i++) {
        int s=read();
        if (s) add_edge(0,i,1,0); else add_edge(i,n+1,1,0);
      }
      for (ri i=1;i<=m;i++) {
        int u=read(),v=read();
        add_edge(u,v,1,1);
      }
      printf("%d
    ",dinic());
    }
  • 相关阅读:
    数据提交
    Python网页信息抓取
    Python语法学习
    Elasticsearch5.x 升级-插件
    LeetCode 33 搜索旋转排序数组
    按之字形顺序打印二叉树
    股票的最大利润
    LeetCode 1143 最长公共子序列
    对称的二叉树
    两个链表的第一个公共结点
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11096405.html
Copyright © 2011-2022 走看看