洛谷P2402 奶牛隐藏
题目背景
这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你。(奶牛混乱的原因看题目描述)
题目描述
在一个农场里有n块田地。某天下午,有一群牛在田地里吃草,他们分散在农场的诸多田地上,农场由m条无向的路连接,每条路有不同的长度。
突然,天降大雨,奶牛们非常混乱,想要快点去躲雨。
已知每个田地都建立有一个牛棚,但是每个牛棚只能容纳一定数量的牛躲雨,如果超过这个数量,那多出的牛只能去别的田地躲雨。
奶牛们每移动1的距离花费1时间,奶牛们想知道它们全部都躲进牛棚,最少需要多少时间。(即最后一头奶牛最少要花多久才能躲进牛棚)。
输入输出格式
输入格式:
第一行输入两个整数N,M。N表示田地块数,M表示路径数。
接下来N行,每行两个整数S,P,分别表示该田地现在有几头牛以及该田地的牛棚最多可以容纳多少牛。
接下来M行,每行3个整数A,B,C,表示存在一条路径连接A,B,并且它的长度为C。
输出格式:
一个整数表示所有奶牛全都躲进牛棚所用的最少时间。如果无法使全部奶牛都躲进牛棚,输出-1。
输入输出样例
说明
【样例解释】
1号点的两只牛直接躲进1号牛棚,剩下的5只中,4只跑去2号点,还有一只从1->2->3,3号点的2只牛也直接躲进去,这样最慢的牛花费的时间是110。
数据范围 : 对于100%的数据,N<=200 M<=1500
题解Here!
一开始看到题目,然后智障一样地以为这是个费用流。。。
但是交上去只有无解的那组过了。。。10分。。。
hack可以这么干:
有3块田,1,2处各有一头牛,2,3处各有一个容量为1的棚,1−>2,2−>3的长度均为1。
如果跑费用流会怎么样?
结果是2,即:将1中的奶牛移到3,2中奶牛不动。
但是显然我们可以将1中的奶牛移到2,2中的奶牛移到3,总时间就是1。
于是这个方法就被hack了。。。
那怎么办呢?
首先我们发现,许多路径是可以不用走的,直接走最短路就好。
注意到n≤200,于是直接Floyd大法。
但是之后呢?
我们发现题目的意思就是:耗时最长的奶牛所用时间最少!
这。。。二分答案啊!
二分一下耗时最长的奶牛所用时间。
然后把所有道路长度大于这个值的路全部砍掉。
注意到我们的目的是让所有奶牛都进入牛棚。
所以我们只要在新的图上跑最大流,得出的答案就是当前图中最多有多少奶牛可以进入牛棚。
这个玩意是有单调性的,所以二分是可行的。
但是每块地有奶牛,有牛棚,怎么办?
没事我们拆个点就好。
将每个点x拆成x,x′。
设num[x]为x的奶牛总数,size[x]是x的牛棚大小。
<u,v,w>为从u到v,流量为w的弧。(包括反向弧)
设立源汇点S,T,连边:<S,x,num[x]>,<x′,T,size[x]>
然后枚举每一对点x,y,若道路长度小于我们二分的值,连边:<x,y′,MAX>,<y,x′,MAX>
然后跑Dinic即可。
如果最大流==奶牛数,就把上限调小;
如果最大流!=奶牛数,就把下限调大。
如果在二分过程中一直都没有最大流==奶牛数,说明根本无解,直接打−1就好。
然后我这个大ZZ又没判−1。。。
结果只有无解的那组没过。。。
和一开始正好相反。。。尴尬。。。
记得开long long!记得开long long!!记得开long long!!!
附带码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | #include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<cstring> #define MAXN 210 #define MAXM 200010 #define MAX (1LL<<60) using namespace std; int n,m,sum=0; int num[MAXN],size[MAXN]; inline int read(){ int date=0; char c=0; while (c< '0' ||c> '9' )c= getchar (); while (c>= '0' &&c<= '9' ){date=date*10+c- '0' ;c= getchar ();} return date; } namespace Floyd{ long long map[MAXN][MAXN]; void floyd(){ for ( int k=1;k<=n;k++) for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) map[i][j]=min(map[i][j],map[i][k]+map[k][j]); } void work(){ int u,v,w; for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++)map[i][j]=(i==j?0:MAX); for ( int i=1;i<=m;i++){ u=read();v=read();w=read(); if (map[u][v]>w)map[u][v]=map[v][u]=w; } floyd(); } } namespace Dinic{ queue< int > q; int s,t,c=2,head[MAXN<<1],deep[MAXN<<1]; struct Edge{ int next,to; long long w; }a[MAXM]; inline void add( int u, int v, long long w){ a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++; a[c].to=u;a[c].w=0;a[c].next=head[v];head[v]=c++; } bool bfs(){ while (!q.empty())q.pop(); int u,v; for ( int i=1;i<=t;i++)deep[i]=0; deep[s]=1; q.push(s); while (!q.empty()){ u=q.front(); q.pop(); for ( int i=head[u];i;i=a[i].next){ v=a[i].to; if (a[i].w&&!deep[v]){ deep[v]=deep[u]+1; if (v==t) return true ; q.push(v); } } } return false ; } long long dfs( int x, long long limit){ if (x==t) return limit; int v; long long sum,cost=0; for ( int i=head[x];i;i=a[i].next){ v=a[i].to; if (a[i].w&&deep[v]==deep[x]+1){ sum=dfs(v,min(a[i].w,limit-cost)); if (sum>0){ a[i].w-=sum; a[i^1].w+=sum; cost+=sum; if (cost==limit) break ; } else deep[v]=-1; } } return cost; } long long dinic(){ long long ans=0; while (bfs())ans+=dfs(s,MAX); return ans; } void rebuild( long long x){ c=2; memset (head,0, sizeof (head)); for ( int i=1;i<=n;i++){ add(s,i,num[i]); add(i+n,t,size[i]); } for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) if (Floyd::map[i][j]<=x)add(i,j+n,MAX); } void work(){ bool flag= false ; long long l=MAX,r=-MAX,mid,ans=MAX; s=n*2+1;t=n*2+2; for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++){ if (Floyd::map[i][j]==MAX) continue ; l=min(l,Floyd::map[i][j]); r=max(r,Floyd::map[i][j]); } while (l<=r){ mid=l+r>>1; rebuild(mid); long long s=dinic(); if (s==sum){ ans=min(ans,mid); flag= true ; r=mid-1; } else l=mid+1; } if (flag) printf ( "%lld\n" ,ans); else printf ( "-1\n" ); } } void init(){ n=read();m=read(); for ( int i=1;i<=n;i++){ num[i]=read();size[i]=read(); sum+=num[i]; } } int main(){ init(); Floyd::work(); Dinic::work(); return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· MQ 如何保证数据一致性?