zoukankan      html  css  js  c++  java
  • bzoj1934: [Shoi2007]Vote 善意的投票

    1934: [Shoi2007]Vote 善意的投票

    Time Limit: 1 Sec  Memory Limit: 64 MB
    Submit: 1891  Solved: 1171
    [Submit][Status][Discuss]

    Description

    幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?

    Input

    第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2。其中n代表总人数,m代表好朋友的对数。文件第二行有n个整数,第i个整数代表第i个小朋友的意愿,当它为1时表示同意睡觉,当它为0时表示反对睡觉。接下来文件还有m行,每行有两个整数i,j。表示i,j是一对好朋友,我们保证任何两对i,j不会重复。

    Output

    只需要输出一个整数,即可能的最小冲突数。

    Sample Input

    3 3
    1 0 0
    1 2
    1 3
    3 2

    Sample Output

    1

    HINT

    在第一个例子中,所有小朋友都投赞成票就能得到最优解

     1 #include<bits/stdc++.h>
     2 #define N 100000
     3 #define inf 2147483647
     4 #define rep(i,l,r) for(int i=l;i<=r;i++)
     5 using namespace std;
     6 struct node{
     7      int to,next,w;
     8 } e[N<<1];
     9 int a,b,ans,dis[N],head[N],tot=1,n,m,T;
    10 inline void ins(int u,int v,int w) {
    11      e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; e[tot].w=w;
    12 }
    13 inline void insert(int u,int v,int w) {
    14      ins(u,v,w); ins(v,u,0);
    15 }
    16 inline bool bfs(){
    17      for(int i=0;i<=T;i++) dis[i]=-1; queue<int>q; q.push(0); dis[0]=0;
    18      while(!q.empty()) {
    19           int x=q.front(); q.pop();
    20           for(int k=head[x];k;k=e[k].next) 
    21              if(dis[e[k].to]<0 && e[k].w>0) {
    22                    dis[e[k].to]=dis[x]+1; q.push(e[k].to);
    23              }
    24      }
    25      if(dis[T]>0) return 1;else return 0;
    26 }
    27 int find(int x,int low){
    28      if(x==T) return low;
    29      int delta=low,now;
    30      for(int k=head[x];k;k=e[k].next) 
    31        if(e[k].w>0 && dis[e[k].to]==dis[x]+1){ 
    32            now=find(e[k].to,min(e[k].w,delta));
    33            e[k].w-=now; e[k^1].w-=now;   delta-=now;
    34            if(!delta) return low;
    35         } 
    36      dis[x]=-1;
    37      return low-delta;
    38 }
    39 int main() {
    40      scanf("%d%d",&n,&m);
    41      T=n+1;
    42      rep(i,1,n) {
    43          scanf("%d",&a);if(!a) insert(0,i,1);else insert(i,T,1);
    44      }
    45      rep(i,1,m) scanf("%d%d",&a,&b),insert(a,b,1),insert(b,a,1);
    46      while(bfs()) ans+=find(0,inf);
    47      printf("%d",ans);
    48 } 
    View Code

    比较裸的割的套路题?(别喷

    S向选1的连容量为1的边 选0的向T连容量为1的边 代表违背意愿的损失

    然后好朋友之间连双向边容量为1 代表好朋友之间冲突的损失

    最小割即答案

  • 相关阅读:
    AcWing 852. spfa判断负环 边权可能为负数。
    面试题 02.01. 移除重复节点
    1114. 按序打印
    剑指 Offer 38. 字符串的排列
    557. 反转字符串中的单词 III
    645. 错误的集合
    面试题 05.03. 翻转数位
    1356. 根据数字二进制下 1 的数目排序
    748. 最短完整词
    剑指 Offer 32
  • 原文地址:https://www.cnblogs.com/Bloodline/p/5885105.html
Copyright © 2011-2022 走看看