zoukankan      html  css  js  c++  java
  • P2057 [SHOI2007]善意的投票 最小割

    $ color{#0066ff}{ 题目描述 }$

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

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

    (color{#0066ff}{输入格式})

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

    (color{#0066ff}{输出格式})

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

    (color{#0066ff}{输入样例})

    3 3
    1 0 0
    1 2
    1 3
    3 2
    

    (color{#0066ff}{输出样例})

    1
    

    (color{#0066ff}{数据范围与提示})

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

    (color{#0066ff}{题解})

    要么投票睡觉,要么投票不睡觉,当然是最小割啦

    不难想到,S向每个点连投票睡觉的边,如果本意投票睡觉,权值就是0,否则就是1

    i向t连投票不睡觉的边,同上

    肯定是割掉谁选谁,我们考虑一对好盆友,如果一个割了左边,一个割了右边,怎么让S仍然流到T呢?

    只需在两人间连双向边就行,只要一个左边,一个右边,就必须割掉中间的边

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int inf = 0x7fffffff;
    const int maxn = 1e5 + 10;
    struct node {
    	int to, can;
    	node *nxt, *rev;
    	node(int to = 0, int can = 0, node *nxt = NULL): to(to), can(can), nxt(nxt) { rev = NULL; }
    };
    node *head[maxn], *cur[maxn];
    int dep[maxn];
    void add(int from, int to, int can) {
    	head[from] = new node(to, can, head[from]);
    }
    void link(int from, int to, int can) {
    	add(from, to, can), add(to, from, 0);
    	(head[from]->rev = head[to])->rev = head[from];
    }
    int n, m, s, t;
    bool bfs() {
    	for(int i = s; i <= t; i++) dep[i] = 0, cur[i] = head[i];
    	std::queue<int> q;
    	q.push(s);
    	dep[s] = 1;
    	while(!q.empty()) {
    		int tp = q.front(); q.pop();
    		for(node *i = head[tp]; i; i = i->nxt) {
    			if(!dep[i->to] && i->can) 
    				dep[i->to] = dep[tp] + 1, q.push(i->to);
    		}
    	}
    	return dep[t];
    }
    int dfs(int x, int change) {
    	if(x == t || !change) return change;
    	int flow = 0, ls;
    	for(node *&i = cur[x]; i; i = i->nxt) {
    		if(dep[i->to] == dep[x] + 1 && (ls = dfs(i->to, std::min(change, i->can)))) {
    			flow += ls;
    			change -= ls;
    			i->can -= ls;
    			i->rev->can += ls;
    			if(!change) break;
    		}
    	}
    	return flow;
    }
    int dinic() {
    	int flow = 0;
    	while(bfs()) flow += dfs(s, inf);
    	return flow;
    }
    
    
    int main() {
    	n = in(), m = in();
    	s = 0, t = n + 1;
    	for(int i = 1; i <= n; i++) {
    		if(in()) link(i, t, 1), link(s, i, 0);
    		else link(s, i, 1), link(i, t, 0);
    	}
    	int x, y;
    	for(int i = 1; i <= m; i++) x = in(), y = in(), link(x, y, 1), link(y, x, 1);
    	printf("%d
    ", dinic());
    	return 0;
    }
    
  • 相关阅读:
    POJ 2411 状态压缩递,覆盖方案数
    POJ 2774 最长公共子串
    POJ 1743 不可重叠的最长重复子串
    POJ 3294 出现在至少K个字符串中的子串
    POJ 3261 出现至少K次的可重叠最长子串
    POJ 1741/1987 树的点分治
    HDU1556 Color the ball
    解决linux系统时间不对的问题
    CentOS 6.9使用Setup配置网络(解决dhcp模式插入网线不自动获取IP的问题)
    Linux网络配置(setup)
  • 原文地址:https://www.cnblogs.com/olinr/p/10550039.html
Copyright © 2011-2022 走看看