bzoj4501 旅行

bzoj4501: 旅行

链接

bzoj

思路

我居然一上来就的去重边,***真可爱。
如果没有修改的话就是一个拓扑dp。
\(f[u]=\sum\frac{f[v]+1}{numson}\)
修改的话a[i]表示这个边要不要。
\(f[u]=\frac{\sum (f[v]+1)*a[i]}{\sum a[i]}\)

第x条边和第y条边的起点是相同的

所以我们拓扑是不会影响的。
所以只要拓扑考虑每个节点最大就好了。
\(f[u]=\frac{\sum (f[v]+1)*a[i]}{\sum a[i]}\)
分母很丑,换一下
\(\sum a[i]*f[u]=\sum (f[v]+1)*a[i]\)
\(\sum a[i]*f[u]-\sum (f[v]+1)*a[i]=0\)
\(\sum a[i](f[u]-f[v]-1)=0\)
然后我们二分答案f[u]。
判定\(\sum a[i](f[u]-f[v]-1)<0\)
这是普通01分数规划的过程。
如何check使得\(\sum a[i](f[u]-f[v]-1)\)最大?
(其实是\(\sum a[i](f[v]+1-f[u])\)最大,不过都一样啦)

第y条边如果被删掉了,那么第x条边也会受到影响,导致x条边被删掉。

就是选x就要选y,可以用最大权闭合子图求,别和我扯2-sat
正权和-最小割

细节

网络流的节点是边的编号。
虽然最终答案精度只要小于\(1e-2\)就行。但是eps还是要开大点\(1e-9\),误差会叠加。
这是有重边的,不要queue去拓扑了,dfs拓扑。
还有,我的网络流板子居然wrong了、、、

代码

#include <bits/stdc++.h>
#define iter vector<int>::iterator
#define iter_Pair vector<pair<int,int> >::iterator
#define eps 1e-9
#define inf 0x7fffffff
using namespace std;
const int N=1007;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
double f[N];
int n,m,k,S,T;
vector<pair<int,int> > xianzhi[N];
pair<int,int> edge[N];
namespace flow {
    struct node {
        int v,nxt;
        double cap;
    }e[N<<5];
    int head[N],dis[N],tot;
    void clear() {
        memset(head,0,sizeof(head));
        tot=1;
    }
    void add_edge(int u,int v,double cap) {
        e[++tot].v=v;
        e[tot].cap=cap;
        e[tot].nxt=head[u];
        head[u]=tot;
    }
    void add(int u,int v,double cap) {
        add_edge(u,v,cap),add_edge(v,u,0.0);
    }
    bool bfs() {
        memset(dis,-1,sizeof(dis));
        queue<int> q;
        q.push(S);
        dis[S]=0;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=e[i].nxt) {
                int v=e[i].v;
                if(dis[v]==-1&&e[i].cap) {
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
            }
        }
        return dis[T]!=-1;
    }
    double dfs(int u,double f) {
       if(u==T) return f;
       double ans=0;
       for(int i=head[u];i;i=e[i].nxt) {
           int v=e[i].v;
           if(dis[v]==dis[u]+1&&e[i].cap&&f) {
               double t=dfs(v,min(e[i].cap,f));
               e[i].cap-=t,e[i^1].cap+=t;
               f-=t,ans+=t;
           }
       }
       return ans;
   }
    double dinic() {
        double ans=0;
        while(bfs()) ans+=dfs(S,inf);
        return ans;
    }
}

struct node {
    int v,nxt,q;
}e[N];
int head[N],tot;
void add(int u,int v) {
    e[++tot].v=v;
    e[tot].nxt=head[u];
    head[u]=tot;
}
bool check(int u,double mid) {
    flow::clear();
    double sum=0;
    for(iter_Pair it=xianzhi[u].begin();it!=xianzhi[u].end();++it)
        flow::add(it->first,it->second,inf);
    for(int i=head[u];i;i=e[i].nxt) {
        double w=1+f[e[i].v]-mid;
        if(w>0) flow::add(S,i,w),sum+=w;
        else flow::add(i,T,-w);
    }
    sum-=flow::dinic();
    return sum>0;
}
void calc(int u) {
    double l=0,r=0;
    for(int i=head[u];i;i=e[i].nxt) r=max(r,f[e[i].v]+1);
    while(r-l>=eps) {
        double mid=(l+r)/2.0;
        if(check(u,mid)) f[u]=l=mid;
        else r=mid;
    }
}
int vis[N];
void tuopu(int u) {
    vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!vis[v]) tuopu(v);   
    }
    calc(u);
}
int main() {
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;++i) {
        int u=read(),v=read();
        edge[i]=make_pair(u,v);
        add(u,v);
    }
    S=1000+1,T=1000+2;
    for(int i=1;i<=k;++i) {
        int x=read(),y=read();
        if(x==y) continue;
        xianzhi[edge[x].first].push_back(make_pair(x,y));
    }
    tuopu(1);
    printf("%.6lf\n",f[1]);
    return 0;
}
全部评论

相关推荐

07-24 03:49
门头沟学院 Java
点赞 评论 收藏
分享
06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务