Proverbs 是一个伟大的探险家,他喜欢到各种各样的地方探险,也热衷于在他探险的地方收集宝藏。这一次他来到了一个上古遗迹,于是proverbs 的寻宝之旅就开始了。
这个遗迹里由N 个密室,想要进每个密室都有一些条件,需要打开一些锁,或是要解一些谜题(至于为什么会有多个,你可以认为它的门是多重的,全开了才可以进去)。但是这些钥匙,或是谜题的答案都在其他密室里,于是他就要先到这些密室(这些谜题太难了,或是太奇葩了,又或proverbs 太蠢了,他不可能通过猜答案来通过,他也不会撬锁,因为他从未有过当盗贼的天赋),于是乎就遇到一些问题。
proverbs 要进a 号密室需要放在b 号密室的钥匙,要进b 号密室需要放在a 号密室的谜题答案,那么这两个密室都进不去了,这对proverbs 来说真是个巨大的打击,但还有更可惜的,有的密室不仅没有财宝,还有各种奇怪的怪物,当然有财宝的密室也可能会有怪物镇守。这些怪物会和proverbs 战斗,proverbs 必须战胜他们,于是proverbs 就会受到伤害,这自然是他不想遇到的(除非他是变态暴力狂,我们这里假设他不是)。对于那些没有锁和谜题的密室,proverbs 就可以直接进去了。
现在proverbs 想知道他每得到一点财富值(财富可以用数字度量)需要受到的最小的伤害值(proverbs 受到的伤害可以数字化,不要问为什么)。如果不可能得到宝藏,那么只要得出这个结论就可以了。现在proverbs有幸得到了遗迹的各种信息,但他并不会解决这个问题,于是就找到了他的好朋友你。
01分数规划后直接跑就好了……
不知道什么事最大权闭合图可以看我的blog
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<deque>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxn=1000+10,maxm=25000+10;
const db inf=100000000,eps=0.000001;
deque<int> dl;
int h[maxn],now[maxn],d[maxn],ru[maxn],go[maxm],fx[maxm],next[maxm];
bool bz[maxn],pp[maxn][maxn];
db dis[maxm],a[maxn],b[maxn];
int i,j,k,s,t,n,m,tot;
db l,r,mid;
void add(int x,int y,db z,int d){
go[++tot]=y;
dis[tot]=z;
fx[tot]=tot+d;
next[tot]=h[x];
h[x]=tot;
}
bool zero(db x){
return x<eps;
}
db dfs(int x,db flow){
bz[x]=1;
if (x==t) return flow;
int r=now[x];
db k;
while (r){
if (!bz[go[r]]&&!zero(dis[r])&&d[x]==d[go[r]]+1){
k=dfs(go[r],min(flow,dis[r]));
if (!zero(k)){
dis[r]=dis[r]-k;
dis[fx[r]]=dis[fx[r]]+k;
now[x]=r;
return k;
}
}
r=next[r];
}
now[x]=0;
return 0;
}
bool change(){
int tmp=100000000,i,r;
fo(i,s,t)
if (bz[i]){
r=h[i];
while (r){
if (!bz[go[r]]&&!zero(dis[r])&&d[go[r]]+1-d[i]<tmp) tmp=d[go[r]]+1-d[i];
r=next[r];
}
}
if (tmp==100000000) return 0;
fo(i,s,t)
if (bz[i]) d[i]+=tmp;
return 1;
}
bool check(db ans){
db x,y=0;
tot=0;
fill(h+s,h+t+1,0);
fill(d+s,d+t+1,0);
int i,j;
fo(i,1,n)
fo(j,1,n)
if (pp[i][j]){
add(i+1,j+1,inf,1);
add(j+1,i+1,0,-1);
}
fo(i,1,n){
x=a[i]-b[i]*ans;
if (x>-eps){
y=y+x;
add(s,i+1,x,1);
add(i+1,s,0,-1);
}
else{
add(i+1,t,-x,1);
add(t,i+1,0,-1);
}
}
db tmp=0,k;
do{
fo(i,s,t) now[i]=h[i];
fill(bz+s,bz+t+1,0);
while (!zero(k=dfs(s,inf))){
tmp=tmp+k;
fill(bz+s,bz+t+1,0);
}
}while (change());
tmp=y-tmp;
return (tmp>eps);
}
bool czy(){
bool p=0;
int now;
fo(i,1,n)
if (!ru[i]) dl.push_back(i);
while (!dl.empty()){
now=dl.front();
dl.pop_front();
bz[now]=1;
fo(i,1,n)
if (pp[i][now]){
ru[i]--;
if (!ru[i]) dl.push_back(i);
}
}
p=1;
fo(i,1,n)
if (bz[i]&&!(fabs(a[i])<eps)){
p=0;
break;
}
return p;
}
int main(){
scanf("%d",&n);
s=1;t=n+2;
fo(i,1,n){
scanf("%d",&k);
while (k--){
scanf("%d",&j);
pp[i][j]=1;
ru[i]++;
}
}
fo(i,1,n)
scanf("%lf%lf",&a[i],&b[i]);
if (czy()){
printf("CanNotFindTreasure!\n");
return 0;
}
l=0;r=10000;
while (r-l>eps){
mid=(l+r)/2;
if (check(mid)) l=mid;else r=mid;
}
printf("%.6lf\n",1/l);
}