zoukankan      html  css  js  c++  java
  • 【bzoj2502】清理雪道 有上下界最小流

    题目描述

    滑雪场坐落在FJ省西北部的若干座山上。
    从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
    你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
    由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。

    输入

    输入文件的第一行包含一个整数n (2 <= n <= 100) – 代表滑雪场的地点的数量。接下来的n行,描述1~n号地点出发的斜坡,第i行的第一个数为mi (0 <= mi < n) ,后面共有mi个整数,由空格隔开,每个整数aij互不相同,代表从地点i下降到地点aij的斜坡。每个地点至少有一个斜坡与之相连。

    输出

    输出文件的第一行是一个整数k – 直升飞机的最少飞行次数。

    样例输入

    8
    1 3
    1 7
    2 4 5
    1 8
    1 8
    0
    2 6 5
    0

    样例输出

    4


    题解

    有源汇有上下界网络流“最小流”

    题目中每条边都可看作上下界为[1,inf]的边。

    对于每个节点x,加入s->x,容量为inf的边,加入x->t,容量为inf的边。

    这样问题就转化为有源汇有上下界网络流。

    再加t->s,容量为inf的边,就变为无源汇问题。

    然后是求最小流。

    最小流的实现方法参照 PoPoQQQ的博客 ,退流的思想很巧妙。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define inf 0x3fffffff
    using namespace std;
    queue<int> q;
    int head[110] , to[30000] , val[30000] , next[30000] , cnt = 1 , dis[110] , s , t , in[110];
    void add(int x , int y , int z)
    {
    	to[++cnt] = y;
    	val[cnt] = z;
    	next[cnt] = head[x];
    	head[x] = cnt;
    }
    bool bfs()
    {
    	int x , i;
    	while(!q.empty()) q.pop();
    	memset(dis , 0 , sizeof(dis));
    	dis[s] = 1;
    	q.push(s);
    	while(!q.empty())
    	{
    		x = q.front() , q.pop();
    		for(i = head[x] ; i ; i = next[i])
    		{
    			if(val[i] && !dis[to[i]])
    			{
    				dis[to[i]] = dis[x] + 1;
    				if(to[i] == t) return 1;
    				q.push(to[i]);
    			}
    		}
    	}
    	return 0;
    }
    int dinic(int x , int low)
    {
    	if(x == t) return low;
    	int temp = low , i , k;
    	for(i = head[x] ; i ; i = next[i])
    	{
    		if(val[i] && dis[to[i]] == dis[x] + 1)
    		{
    			k = dinic(to[i] , min(temp , val[i]));
    			if(!k) dis[to[i]] = 0;
    			val[i] -= k , val[i ^ 1] += k;
    			if(!(temp -= k)) break;
    		}
    	}
    	return low - temp;
    }
    int main()
    {
    	int n , i , c , y , ans , tempid;
    	scanf("%d" , &n);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d" , &c);
    		while(c -- )
    		{
    			scanf("%d" , &y);
    			in[i] -- , in[y] ++ ;
    			add(i , y , inf) , add(y , i , 0);
    		}
    	}
    	add(n + 1 , 0 , inf) , tempid = cnt , add(0 , n + 1 , 0);
    	s = n + 2 , t = n + 3;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		add(0 , i , inf) , add(i , 0 , 0);
    		add(i , n + 1 , inf) , add(n + 1 , i , 0);
    		if(in[i] > 0) add(s , i , in[i]) , add(i , s , 0);
    		if(in[i] < 0) add(i , t , -in[i]) , add(t , i , 0);
    	}
    	while(bfs()) dinic(s , inf);
    	for(i = head[s] ; i ; i = next[i]) val[i] = val[i ^ 1] = 0;
    	for(i = head[t] ; i ; i = next[i]) val[i] = val[i ^ 1] = 0;
    	ans = val[tempid ^ 1];
    	val[tempid] = val[tempid ^ 1] = 0;
    	add(s , n + 1 , inf) , add(n + 1 , s , 0);
    	add(0 , t , inf) , add(t , 0 , 0);
    	while(bfs()) ans -= dinic(s , inf);
    	printf("%d
    " , ans);
    	return 0;
    }
  • 相关阅读:
    面向对象高级
    Intellij IDEA 激活码 | Intellij IDEA 注册码
    如何保证核心链路稳定性的流控和熔断机制?
    消息模型:主题和队列有什么区别?
    MySQL中悲观锁和乐观锁到底是什么?
    SQL是如何在数据库中执行的?
    ZooKeeper 面试题(30道ATM精选问题)
    线上服务的FGC问题排查,看这篇就够了!
    一次线上JVM调优实践,FullGC40次/天到10天一次的优化过程
    由多线程内存溢出产生的实战分析
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6516681.html
Copyright © 2011-2022 走看看