bzoj 1934(最小割)

11 篇文章 0 订阅

1934: [Shoi2007]Vote 善意的投票

Time Limit: 1 Sec   Memory Limit: 64 MB
Submit: 1689   Solved: 1041
[ 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

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


解题思路:我终于找到打最小割的正确姿势了。不多讲,简单建图,最大流。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,len=1,ans;
int to[100000],next[100000],zhi[100000];
int h[310],dis[310];
int q[100000];


inline int read()
{
char y;int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y,int z)
 {
  ++len;
  to[len]=y; next[len]=h[x]; h[x]=len; zhi[len]=z;
 }


bool bfs()
 {
  memset(dis,-1,sizeof(dis)); dis[0]=0;
  int tail=0,head=0; ++tail; q[tail]=0;
  while (head<tail)
  {
  ++head;
  int u=h[q[head]];
  while (u!=0)
  {
  if (dis[to[u]]==-1 && zhi[u]>0)
{
    dis[to[u]]=dis[q[head]]+1;
    ++tail; q[tail]=to[u];
 }
u=next[u]; 
}
 }
if (dis[n+1]!=-1) return true;else return false;
 }


int dicnic(int sum,int now)
 {
  if (now==n+1) return sum;
  int sug=0;
  int u=h[now];
  while (u!=0)
  {
  if (zhi[u]>0 && dis[to[u]]==dis[now]+1)
  {
  int s=dicnic(min(sum-sug,zhi[u]),to[u]);
  sug+=s; zhi[u]-=s; zhi[u^1]+=s;
  if (sug==sum) return sug;
  }
  u=next[u];
}
if (sug==0) dis[now]=-1;
return sug;
 }


int main()
{
   n=read(); m=read();
   for (int i=1;i<=n;++i)
    {
    int x; x=read();
    if (x==1)
    {
    insert(0,i,1); insert(i,0,0);
    insert(i,n+1,0); insert(n+1,i,0);
}else
 {
  insert(0,i,0); insert(i,0,0);
    insert(i,n+1,1); insert(n+1,i,0);
 }
}
   for (int i=1;i<=m;++i)
    {
    int x,y;
    x=read(); y=read();
    insert(x,y,1); insert(y,x,1);
}
   ans=0;
   while (bfs())
    {
      ans+=dicnic(0x7fffffff,0);
}
   printf("%d",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值