zoukankan      html  css  js  c++  java
  • 【洛谷P2057】善意的投票 / 冠军调查

    题目

    题目链接:https://www.luogu.com.cn/problem/P2057
    幼儿园里有 \(n\) 个小朋友打算通过投票来决定睡不睡午觉。

    对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。

    虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。

    我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。

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

    思路

    第一道完全自己想的一次过的网络流题 /fad。
    我们从源点 \(S\) 向投 \(1\) 的人连一条流量为 \(1\) 的边,从投 \(0\) 的人向汇点 \(T\) 连一条流量为 \(1\) 的边。
    然后对于一对朋友 \(u,v\),如果他们投票相同,那么互相连一条流量为 \(1\) 的边,否则从投 \(1\) 的人向投 \(0\) 的人连一条流量为 \(1\) 的边。
    这样我们就保证了如果存在一条路径 \(S\to x\to y\to T\),割 \(x\to y\) 相当于 \(x\)\(y\) 都不改票;割 \(S\to x\)\(y\to T\) 都相当于改变选票,但是改变选票的人的其他好友依然可以有流量流向他,所以还是需要断掉其他边。
    此时这张图的最小割就是答案。跑最大流即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=310,M=N*N*4,Inf=1e9;
    int n,m,S,T,maxf,tot=1,head[N],a[N],cur[N],dep[N];
    
    struct edge
    {
    	int next,to,flow;
    }e[M];
    
    void add(int from,int to,int flow)
    {
    	e[++tot].to=to;
    	e[tot].flow=flow;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    bool bfs()
    {
    	memcpy(cur,head,sizeof(cur));
    	memset(dep,0x3f3f3f3f,sizeof(dep));
    	queue<int> q; q.push(S);
    	dep[S]=1;
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i].flow && dep[v]>dep[u]+1)
    			{
    				dep[v]=dep[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return dep[T]<Inf;
    }
    
    int dfs(int x,int flow)
    {
    	if (x==T)
    	{
    		maxf+=flow;
    		return flow;
    	}
    	int used=0,ret;
    	for (int i=cur[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (e[i].flow && dep[v]==dep[x]+1)
    		{
    			ret=dfs(v,min(flow-used,e[i].flow));
    			e[i].flow-=ret; e[i^1].flow+=ret;
    			used+=ret;
    			if (used==flow) return flow;
    		}
    	}
    	return used;
    }
    
    void dinic()
    {
    	while (bfs())
    		dfs(S,Inf);
    }
    
    int main()
    {
    	S=N-1; T=N-2;
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		if (a[i]) add(S,i,1),add(i,S,0);
    			else add(i,T,1),add(T,i,0);
    	}
    	for (int i=1,x,y;i<=m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		if (a[y]==1) swap(x,y);
    		if (a[x]==a[y]) add(x,y,1),add(y,x,1);
    			else add(x,y,1),add(y,x,0);
    	}
    	dinic();
    	printf("%d",maxf);
    	return 0;
    }
    
  • 相关阅读:
    JDBC编程
    解决eclipse的source not found change at.
    Python 学习笔记
    网络编程(二) 多线程
    wpf 如何设置滚动条在超出范围的时候才显示?(转)
    WPF datagrid 如何隔行变色
    如果DataGrid的checkbox出现点一个另外自动点另一个现象
    WPF之DataGrid应用(转)
    WPF qq界面(转)
    SQL中distinct的用法(转)
  • 原文地址:https://www.cnblogs.com/stoorz/p/13790049.html
Copyright © 2011-2022 走看看