[ZJOI2010]贪吃的老鼠
很不错的一道网络流的题目
二分答案是显然的
首先不考虑每个饼干只能一个老鼠吃
那很显然的建图就是将时间点按照开始结束的点分成2*n-1段
然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可以运行的饼干
那么考虑加上限制每个饼干只能被一个老鼠吃
我们可以考虑一下进行差分
将s-老鼠的值变成差分后的值(当然还得乘以相应个数) 同理老鼠到饼干也类似的连(就不用乘以相应个数了)
为什么这样做是可以的呢?
因为 我们可以把每一个决策都用这里差分的值来表示出来
那还有一个问题就是有的状态实际上是看似不存在的
比如有v1,v2,v3
那么如果没有v2-v1,v1只有v3-v2这个状态实际是不存在的
但是这个一定是比v3状态吃的要小的,即用比限制时间少的v3是一定能达到这个状态的
所以这个是对的
另外:由于几乎没用过c++实数的原因 被坑的很惨
刚开始以为是eps出问题导致精度不足。。后来发现对于精度要求高这不能用cout
long double在精度上高于double
输出时要转换成double输出
#include <bits/stdc++.h> using namespace std; #define ll long long const ll maxn=200000; #define INF 1e9 #define exp 1e-6 ll n,m,s,t,l,sum; ll head[maxn],d[maxn],p[maxn],r[maxn]; ll dd[maxn],ss[maxn]; bool vis[maxn]; struct re{ ll a,b; long double c,flow; }a[maxn]; void arr(ll x,ll y,long double z) { a[++l].a=head[x]; a[l].b=y; a[l].c=z; a[l].flow=0; head[x]=l; } bool bfs() { memset(vis,0,sizeof(vis)); queue<ll> q; q.push(s); d[s]=0; vis[s]=1; while (!q.empty()) { ll x=q.front();q.pop(); ll u=head[x]; while (u) { ll v=a[u].b; if (!vis[v]&&a[u].c>a[u].flow) { vis[v]=1; d[v]=d[x]+1; q.push(v); } u=a[u].a; } } return vis[t]; } long double dfs(ll x,long double y) { if (x==t||y==0) return y; long double flow=0,f; ll tmp; ll u=head[x]; while (u) { ll v=a[u].b; if (d[x]+1==d[v]&&(f=dfs(v,min(y,a[u].c-a[u].flow)))>0) { a[u].flow+=f; if (u%2) tmp=u+1; else tmp=u-1; y-=f; a[tmp].flow-=f; flow+=f; if (y==0) break; } u=a[u].a; } return flow; } long double maxflow() { long double flow=0; while (bfs()) { flow+=dfs(s,INF); } return flow; } struct ree{ long double a; ll b; }b[maxn]; bool cmp(ree a,ree b) { return(a.a<b.a); } bool cmp2(ll x,ll y) { return(x<y); } bool check(long double x) { for (ll i=1;i<=n;i++) { b[i*2-1].a=r[i]; b[i*2].a=dd[i]+x; b[i*2].b=i*2; b[i*2-1].b=i*2-1; } sort(b+1,b+2*n+1,cmp); l=0;memset(head,0,sizeof(head)); ll last2=0; s=0; t=(2*n-1)*m+n+1; for (ll i=1;i<=n;i++) { arr((2*n-1)*m+i,t,p[i]); arr(t,(2*n-1)*m+i,0); } for (ll i=1;i<=2*n-1;i++) { for (ll j=1;j<=m;j++) { arr(0,j+last2,(m-j+1)*(ss[j]-ss[j-1])*(b[i+1].a-b[i].a)); arr(j+last2,0,0); } for (ll k=1;k<=n;k++) if (r[k]<=b[i].a&&dd[k]+x>=b[i+1].a) for (ll j=1;j<=m;j++) { arr(j+last2,(2*n-1)*m+k,(b[i+1].a-b[i].a)*(ss[j]-ss[j-1])); arr((2*n-1)*m+k,j+last2,0); } last2+=m; } ll to=maxflow(); if (to==sum) return(1); else return (0); } int main() { freopen("cheese.in","r",stdin); freopen("cheese.out","w",stdout); ll T; cin>>T; for (ll i=1;i<=T;i++) { cin>>n>>m; sum=0; for (ll i=1;i<=n;i++) { cin>>p[i]>>r[i]>>dd[i]; sum+=p[i]; } for (ll i=1;i<=m;i++) cin>>ss[i]; sort(ss+1,ss+m+1,cmp2); long double hh=0,tt=1e9; while ((tt-hh)>exp) { long double mid=(hh+tt)/2; if (check(mid)) tt=mid; else hh=mid; } double tmp=tt; printf("%.9f\n",tmp); } return 0; }