1287. 躲雨

2023-10-23 16:30
文章标签 躲雨 1287

本文主要是介绍1287. 躲雨,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

  FJ的奶牛真的很怕雨,所以一下雨他们就急着要找地方躲雨。为了做好防雨准备,他们装了警报器,一有雨就拉响警报器,他们利用天气预报来预测雨的到来,但有时候不准导致拉错警报,为了减少拉错警报的可能,他们想在保证奶牛有足够时间躲起来的前提下尽可能晚地拉响警报。
  农场有F(1<=F<=200)个奶牛吃草的区域,有P(1<=P<=1500)条路连接一些区域,路是双向的。有些区域有遮雨棚,每个遮雨棚有自己的容量限制。
  现在要你计算所有牛都能找到地方躲雨最少需要多少时间。

Input

  第1行:两个空格隔开的整数F和P
  第2到F+1行:每行两个空格隔开的整数X,Y,X表示当前这个区域的牛的数量,Y表示该区域的遮雨棚最多只能容纳Y头牛。
  第F+2到F+P+1行:3个空格隔开的整数a,b,c,表示a和b之间有一条长度为c的路直接相连。

Output

  输出一个整数,表示所有牛都能在这个时间内到达遮雨棚。

Sample Input

3 4
7 2
0 4
2 6
1 2 40
3 2 70
2 3 90
1 3 120

Sample Output

110

Data Constraint

Hint

【样例说明】
  1号区域里保留2头牛,4头牛去2号区域,还有1个去3号区域,3号区域的2头牛保持不动,可能还有其他方案,但110是最少的时间。

Source / Author: USACO

 

 

 

题解:

二分,二分图匹配。

有一种方法是把每个节点拆开成x[i]+y[i]个来匈牙利,但匈牙利O(n+m)。

考虑网络流。

先预处理dis[i][j]为i到j的距离。

建图:

原点给1~n 点连一条流量为x的边。

汇点给1'~n'连一条流量为y的边。

1~n 给 1'~n'  连一条流量为INF的边。

(条件:若i要给j一条边,则dis[i][j]<=mid)

 

然后做一次最大流。

  1. 初始弧优化
  2. 分层图优化 
  3. gap优化

最大流sap算法:详见:https://blog.csdn.net/Com_man_der/article/details/94645092

初始弧:

dg中记录一个点走到哪条边了,下次只用接着往后枚举。

分层图优化 :

所谓距离标号 ,就是某个点到汇点的最少的弧的数量dis,走的时候只走允许弧(dis[i] = dis[j+1] i----->j)

gap优化:

gap[i]数组表示距离标号为i的点有多少个,如果到某一点没有符合距离标号的允许弧,那么需要修改距离标号来找到增广路; 如果重标号使得gap数组中原标号数目变为0,则算法结束。

 

  1. #include<bits/stdc++.h>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define ll long long
    #define rint register int
    #define N 2010
    #define M 500010
    #define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
    #define INF 2147483647
    using namespace std;struct edge
    {ll v,fr,d,t; ll c;};//注意d是不变的,c是剩余流量 ll n,m,i,j,k,t,ans,tmp1,tmp2;
    ll x[N],y[N];
    ll l,r,mid;
    ll tail[N],tot=1; edge e[M];
    ll dis[N],gap[N],cur[N],S,T;
    ll floyd[N][N];void init_dis()
    {for(rint i=1;i<=n;i++)floyd[i][i]=0;for(rint k=1;k<=n;k++)for(rint i=1;i<=n;i++)for(rint j=1;j<=n;j++)(floyd[i][j] = min(floyd[i][j] , floyd[i][k] + floyd[k][j]));return ;
    }void add(ll u,ll v,ll d,ll t)
    {e[++tot].v=v;e[tot].d = e[tot].c = d;e[tot].t=t;e[tot].fr=tail[u];tail[u]=tot;
    }void turn_back()
    {for(rint i=2;i<=tot;i++)e[i].c=e[i].d;return ;
    }void build_graph()
    {for(i=1;i<=n;i++)add(0,i,x[i],0),add(i,0,0,0);//for(i=1;i<=n;i++)for(j=1;j<=n;j++) add(i,j+n,INF,floyd[i][j]),add(j+n,i,0,floyd[j][i]);//for(i=1;i<=n;i++)add(i+n,2*n+1,y[i],0) , add(2*n+1,i+n,0,0);//return ;// 最后的点数为1+n+n+1 : 0 -- 2*n+1 ; 0为源点 ; n*2+1为汇点。 
    }ll dfs(ll k,ll flow)
    {if(k==T)return flow;ll have=0;for(ll p=cur[k];p;p=e[p].fr)if(e[p].t <= mid){ll &v=e[p].v,&c=e[p].c;if(dis[k] -1 == dis[v] && c){cur[k] = p;ll now = dfs(v, min(flow - have,c));c-= now;e[p^1].c+=now;have+=now;if(have == flow)return flow;}}	cur[k] = tail[k];if(!(--gap[dis[k]])) dis[S]=T;gap[++dis[k]]++;return have;
    }ll check()
    {mem(gap,0);mem(dis,0);rint i=0,j=0;S=0,T=n*2+1;for(i=0;i<=T;i++)cur[i] = tail[i];turn_back();gap[0] = T+1;while(dis[S] < T+1) dfs(S,INF);ll p =tail[0];for( ;p;p=e[p].fr)if(e[p].c>0) break;return !p;
    }void binary()
    {l=0;r=r;ans=-1;while(l<=r){mid=(l+r)/2;if(check()){ans = mid;r = mid-1;}else l=mid+1;}return ;
    }int main()
    {open("rain");scanf("%lld%lld",&n,&m);for(i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);ll u,v,d;mem(floyd,60);for(i=1;i<=m;i++)scanf("%lld%lld%lld",&u,&v,&d),(floyd[u][v]=floyd[v][u]=min(floyd[v][u],d)),r+=d;init_dis();build_graph();binary();printf("%lld",ans);return 0;	
    }

     

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

这篇关于1287. 躲雨的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/269027

相关文章

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

POJ 1287 Networking

Kruskal建图更加方便,不管三七二十一全部扔进去排序,然后并查集会自动帮助我们去重的。建图之后裸最小生成树 /************************************************ Author: fisty* Created Time: 2015/2/28 13:03:03* File Name : B.cpp*******************

51nod 1287 加农炮(二分/线段树)

1287 加农炮 题目来源:  Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题  收藏  关注 一个长度为M的正整数数组A,表示从左向右的地形高度。测试一种加农炮,炮弹平行于地面从左向右飞行,高度为H,如果某处地形的高度大于等于炮弹飞行的高度H(A[i] >= H),炮弹会被挡住并落在i - 1处

#堆优化dijkstra#洛谷 1828 jzoj 1287 codevs 2038 ssl 1693 香甜的黄油

题目 有 n n n个点,求每个点的单源最短路径的最短和 分析 其实跑 n n n遍 s p f a spfa spfa或 d i j k s t r a dijkstra dijkstra堆优化就行了 代码 #include <cstdio>#include <queue>struct node{int y,w,next;}e[2901];int n,m,dis[801]

Codeforces 1287(A,B,C)round#612(Div.2)

传送门 A. Angry Students 题意:给你一串字符由"A","P"组成,左侧的A会每秒感染右侧相邻的一个P,问多少秒后右侧全部的P被感染完。 思路:直接找到每个A后面有几个A连续在一起,找到这个最大值输出即可。 AC代码: #include<bits/stdc++.h>using namespace std;#define rep(i,a,n) for(int i=a;i

caioj.cn 1118:网络流入门4:牛躲雨

1118: [视频]网络流入门4:牛躲雨 时间限制: 1 Sec   内存限制: 128 MB 提交: 173   解决: 44 [ 提交][ 状态][ 讨论版] 题目描述 【问题描述】 下雨了,有F (1 <= F <= 200) 个牛棚,这F个牛棚之间有P (1 <= P <= 1500)条无向边(这些边长度会给出,牛每个单位时间走一个单位的距离)。 每个牛棚有两个值A和B(