【Luogu】P3705新生舞会(费用流+分数规划+二分答案)

  题目链接

  本来以为自己可以做出来,结果……打脸了

  (貌似来wc立了好几个flag了,都没竖起来)

  不过乱蒙能蒙出一个叫“分数规划”的东西的式子还是很开心的

  观察$C=\frac{a_{1}+a_{2}+.......+a_{n}}{b_{1}+b_{2}+.....b_{n}}$

  然后可以把分母乘到左边

  然后可以把C乘进去

  然后二分C,建图求最大权匹配,判断跟答案的关系。

  

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 450
#define eps 1e-7
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘0‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int from,next,to,val;
    double dis;
}edge[maxn*maxn*3];
int head[maxn],num;
inline void addedge(int from,int to,int val,double dis){
    edge[++num]=(Edge){from,head[from],to,val,dis};
    head[from]=num;
}
inline void add(int from,int to,int val,double dis){
    addedge(from,to,val,dis);
    addedge(to,from,0,-dis);
}
inline void clear(){    memset(head,0,sizeof(head));    num=0;    }
inline int count(int i){    return i&1?i+1:i-1;    }

double dis[maxn];
int pre[maxn];
int flow[maxn];
bool vis[maxn];
int d[maxn][maxn];
int w[maxn][maxn];
int Start,End;
int n;

double spfa(){
    for(int i=Start;i<=End;++i)    dis[i]=-0x7fffffff; dis[Start]=0;
    queue<int>q; q.push(Start);    memset(flow,0,sizeof(flow)); flow[Start]=0x7fffffff;
    while(!q.empty()){
        int from=q.front();    q.pop();    vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(edge[i].val<=0||dis[to]>=dis[from]+edge[i].dis)    continue;
            dis[to]=dis[from]+edge[i].dis;
            pre[to]=i;    flow[to]=min(flow[from],edge[i].val);
            if(vis[to])    continue;
            vis[to]=1;    q.push(to);
        }
    }
    if(flow[End]==0)    return 0;
    int now=End;
    while(now!=Start){
        //printf("D");
        int i=pre[now];
        edge[i].val-=flow[End];
        edge[count(i)].val+=flow[End];
        now=edge[i].from;
    }
    return dis[End];
}

bool payflow(double lim){
    clear();
    for(int i=1;i<=n;++i){
        add(Start,i,1,0);
        add(i+n,End,1,0);
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)    add(i,j+n,1,1.0*d[i][j]-1.0*w[i][j]*lim);
    double ret=0;
    while(1){
        double now=spfa();
        if(fabs(now)<=eps)    break;
        ret+=now;
    }
    return ret>0;
}

int main(){
    n=read();    End=n*2+1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)    d[i][j]=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)    w[i][j]=read();
    double l=0,r=1e4;double ans=0;
    while(r-l>eps){
        double mid=(l+r)/2.0;
        if(payflow(mid)){
            ans=mid;
            l=mid;
        }
        else    r=mid;
    }
    printf("%.6lf",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/cellular-automaton/p/8425797.html

时间: 2024-08-28 14:42:01

【Luogu】P3705新生舞会(费用流+分数规划+二分答案)的相关文章

[BJOI2019]奥术神杖——AC自动机+DP+分数规划+二分答案

题目链接: [BJOI2019]奥术神杖 答案是$ans=\sqrt[c]{\prod_{i=1}^{c}v_{i}}=(\prod_{i=1}^{c}v_{i})^{\frac{1}{c}}$. 这样不大好求,我们将这个式子取$ln$,变成$ln\ ans=\frac{1}{c}\sum_{i=1}^{c}ln\ v_{i}$. 这显然是一个分数规划,每次二分一个答案$mid$,将每个串的权值都减去$mid$,那么只需要求最大价值是否大于$0$即可. 剩下的问题就是一个在$AC$自动机上的$D

hdu6070(分数规划/二分+线段树区间更新,区间最值)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6070 题意: 给出一个题目提交序列, 从中选出一个正确率最小的子串. 选中的子串中每个题目当且仅当最后一次提交是正确的. 思路: 分数规划 二分答案, 然后在 check 函数中查找是否存在某个区j间 [l, r] 使得 sum(l, r) / (r - l + 1) <= mid, 即 sum(l, r) + l * mid <= (r + 1) * mid. 可以用个线段树来维护 sum(l

POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目是要求一棵最优比率生成树. 解题思路: 对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案. 0-1规划是啥? 概念有带权图G, 对于图中每条

poj2728 Desert King --- 01分数规划 二分水果。。

这题数据量较大,普通的求MST是会超时的. d[i]=cost[i]-ans*dis[0][i] 据此二分. 但此题用Dinkelbach迭代更好 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; #define N 1010 double mp[N][N],c[N][N],x

[Usaco2007 Dec][BZOJ1690] 奶牛的旅行|分数规划|二分|SPFA

1690: [Usaco2007 Dec]奶牛的旅行 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 700  Solved: 363[Submit][Status][Discuss] Description 作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天.旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇. 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了城市中所有L(2 <= L <= 1000)座标志

bzoj1690:[Usaco2007 Dec]奶牛的旅行 (分数规划 &amp;&amp; 二分 &amp;&amp; spfa)

用dfs优化的spfa判环很快啦 分数规划的题目啦 二分寻找最优值,用spfa判断能不能使 Σ(mid * t - p) > 0 最优的情况只能有一个环 因为如果有两个环,两个环都可以作为奶牛的行程,如果两个环单独计算的结果不一样,那么两个环中比值更大的才是最优解,如果结果一样,多算一个环就没有意义了. 代码如下 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespa

51nod 1257 01分数规划/二分

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1257 1257 背包问题 V3 基准时间限制:3 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 N个物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数),从中选出K件物品(K <= N),使得单位体积的价值最大. Input 第1行:包括2个数N, K(1 <= K <=

luogu P2053 [SCOI2007]修车 |费用流

题目描述 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小. 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间. 输入格式 第一行有两个数M,N,表示技术人员数与顾客数. 接下来n行,每行m个整数.第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T. 输出格式 最小平均等待时间,答案精确到小数点后2位. #includ

POJ 3621(0/1分数规划,二分) Sightseeing Cows

题意 给一个n个点m条边的图,每一个点和每一条边都有权值.现在要找一个环的点权和/边权和最大,求这个最大值. 思路 SPFA+二分 题目的关系式:点权和/边权和 <= ans 转换一下就变成 ans*边权和 - 点权和 >= 0; 二分答案,然后用SPFA去check是否存在一个负权回路. 参考code: /* #pragma warning (disable: 4786) #pragma comment (linker, "/STACK:0x800000") */ #in