网络流 p2507 模板题学习建图

题目描述

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

我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?

输入输出格式

输入格式:

 

文件的第一行只有两个整数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不会重复。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 

3 3
1 0 0
1 2
1 3
3 2

输出样例#1: 

1

说明

2≤n≤300,1≤m≤n(n-1)/2。

 

 

这题几乎就是刻意为了考网络流而出的一道题,很裸很水的一道题,主要是通过这道题学习怎样建图

一个人,要么和自己冲突,要么和所有朋友冲突,最后所有人必须做出选择;

映射到图上就是 引入超级源点s 同意午睡,超级汇点t反对午睡,同意午睡的人与源点相连,反对午睡的人与汇点项链,当人们与自己意愿相背的时候就要需要割断与s或t的边,每个人与自己的朋友也连一条边,当朋友不在一个阵营时就把边割断,最后划分为与源点相连的一个阵营,和与汇点相连的一个阵营,求出割断边的权值和最小,就是求最小割,上模板就完事了,也没有要求的其他条件,

以下给出ac代码:

```

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>

using namespace std;
const int maxn=5100,maxm=2e6+7,inf=0x7f7f7f7f;
int h[maxn],e[maxm],ne[maxm],idx,w[maxm];
int dep[maxn];
int n,m,s,t;

void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool bfs(int s,int t){
    memset(dep,-1,sizeof dep);
    queue<int>q;q.push(s);dep[s]=1;
    while(q.size()){
        int u=q.front();q.pop();
        if(u==t)break;
        for(int i=h[u];~i;i=ne[i]){
            int j=e[i];
            if(dep[j]==-1&&w[i])q.push(j),dep[j]=dep[u]+1;
        }
    }
    return dep[t]!=-1;
}
int dfs(int x,int v){
    if(x==t||v==0)return v;
    int f,res=0;
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(dep[j]==dep[x]+1&&w[i]){
            f=dfs(j,min(w[i],v));
            w[i]-=f,w[i^1]+=f,v-=f,res+=f;
            if(v==0)break;
        }
    }
    return res;
}
int main()
{
    int a,b,c;
    s=0,t=5005;
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        if(a){add(s,i,1);add(i,s,0);}
        else {add(i,t,1);add(t,i,0);}
    }
    for(int i=0;i<m;i++){
        scanf("%d%d",&a,&b);
        add(a,b,1);add(b,a,1);
    }
    int ans=0;
    while(bfs(s,t))ans+=dfs(s,inf);
    printf("%d\n",ans);
    return 0;
}
 

```

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值