【POJ3155】Hard Life 分数规划+最小割

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/46437961");
}

题解:

如题。先算出那个分数值,然后看有哪些人还与源点相连。

最小割建图:原图每个点对应一个点,原图每条边对应一个点。每条边对应点向两端点对应点连边,注意要单向边。

这道题卡精度:

所以一些细节问题扒代码吧Qwq

eps:1e-5

因为是double网络流,所以二分上界别太大,边数就好。

另外这份代码在BZOJ并不能AC、

而在BZOJ能AC的代码也并不一定能在POJ上AC、

什么鬼。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 12000
#define M 70000
#define eps 1e-6
#define inf 0x3f3f3f3f
using namespace std;
struct ELi
{
    int v,n;
    double l;
}e[M];
int head[N],cnt;
inline void add(int u,int v,double l)
{
    e[++cnt].v=v;
    e[cnt].l=l;
    e[cnt].n=head[u];
    head[u]=cnt;
}
inline void Add(int u,int v,double l)
{add(u,v,l),add(v,u,0);}
int s,t,dep[N];
queue<int>q;
bool bfs()
{
    while(!q.empty())q.pop();
    memset(dep,0,sizeof dep);
    q.push(s),dep[s]=1;
    int i,u,v;
    while(!q.empty())
    {
        u=q.front(),q.pop();
        for(i=head[u];i;i=e[i].n)
        {
            if(!dep[v=e[i].v]&&e[i].l>eps)
            {
                dep[v]=dep[u]+1;
                if(v==t)return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
double dinic(int x,double flow)
{
    if(x==t)return flow;
    int i,v;
    double remain=flow,k;
    for(i=head[x];i&&remain>eps;i=e[i].n)
    {
        if(dep[v=e[i].v]==dep[x]+1&&e[i].l>eps)
        {
            k=dinic(v,min(remain,e[i].l));
            if(k<eps)dep[v]=0;
            e[i].l-=k,e[i^1].l+=k;
            remain-=k;
        }
    }
    return flow-remain;
}
int U[N],V[N],n,m;
bool check(double mid)
{
    int i;
    memset(head,0,sizeof head);

    for(cnt=i=1;i<=m;i++)
    {
        Add(n+i,U[i],inf);
        Add(n+i,V[i],inf);
    }
    for(i=1;i<=n;i++)Add(i,t,mid);
    for(i=1;i<=m;i++)Add(s,n+i,1);

    double maxflow=m;
    while(bfs())
        maxflow-=dinic(s,inf);
    return maxflow>eps;
}
int main()
{
//  freopen("test.in","r",stdin);
    int i;

    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!m)
        {
            puts("1\n1");
            continue;
        }
        s=0,t=n+m+1;
        for(i=1;i<=m;i++)scanf("%d%d",&U[i],&V[i]);

        double l=0,r=m,mid;
        while(l+1e-5<r)
        {
            mid=(l+r)/2.0;
            if(check(mid))l=mid;
            else r=mid;
        }
        check(l),bfs();

        int ans=0;
        for(i=1;i<=n;i++)if(dep[i])ans++;
        printf("%d\n",ans);

        for(i=1;i<=n;i++)if(dep[i])
            printf("%d\n",i);
    }
    return 0;
}
时间: 2024-12-10 17:56:58

【POJ3155】Hard Life 分数规划+最小割的相关文章

【BZOJ3232】圈地游戏 分数规划+最小割

[BZOJ3232]圈地游戏 Description DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用. DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外).记这条封闭路线内部的格子总价值为V,路线上的费用总和为C,DZY想知道V/C的最大值是多少. Input 第一行为两个正整数n,m. 接下来n行,每行m个非负整数,表示对应格子的价值. 接下来n

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的

bzoj 3232: 圈地游戏【分数规划+最小割】

数组开小导致TTTTTLE-- 是分数规划,设sm为所有格子价值和,二分出mid之后,用最小割来判断,也就是判断sm-dinic()>=0 这个最小割比较像最大权闭合子图,建图是s像所有点连流量为格子价值的边(相当于最大权闭合子图中的正权点),然后考虑边缘,两个相邻的格子,如果一个选一个不选那么中间这条边就有负的贡献,所以两个相邻的格子之间连两条边权为mid*边权的边,注意是两条,要互相连一下,然后所有边界上的点像t连边权为mid*边界边权的边,相当于假装外面还有一层点全标为t,然后跑最小割判断

HDU 2676 Network Wars 01分数规划,最小割 难度:4

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1676 对顶点i,j,起点s=1,终点t=n,可以认为题意要求一组01矩阵use[i][j],使得aveCost=sigma(use[i][j]*cost[i][j])/sigma(use[i][j])最小,且{(i,j)|use[i][j]==1}是图的S-T割 定义F(e)=min(sigma(use[i][j]*(cost[i][j]-a))),明显,F(e)是目标式的变

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

zoj 2676 Network Wars 最小割+0-1分数规划

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 题意: 给出N个点和M条边,要求一个割集,使得集合中 ans = 所有边点权值和/边的数量 最小. 思路: 0-1分数规划. 具体证明参考 胡伯涛 <最小割模型在信息学竞赛中的应用> 设g = min(Σwi/Σ1) 转化为 求g使得 (Σwi - g*Σ1) = 0. 所以二分求g的值. 每次建图的时候,以1为源点,N为汇点. 原来图中每条边的容量

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

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

【bzoj1486】[HNOI2009]最小圈 分数规划+Spfa

题目描述 样例输入 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 3 样例输出 3.66666667 题解 分数规划+Spfa判负环 二分答案mid,并将所有边权减去mid,然后再判负环,若有负环则调整下界,否则调整上界,直至上下界基本重合. 证明:显然 由于有(c+d)/(a+b+k)>(c+d)/(a+b)≥min(c/a,d/b),所以两个相交环形成的新环一定不是最优解,即答案一定是简单环. 如果存在环使得边权和/点数<mid,那么就有边权和<点数*mid. 又因

【BZOJ1486】【HNOI2009】最小圈 分数规划 dfs判负环。

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46348771"); } 题解: 分数规划Qwq. 然而它卡判点入n次的那种spfa推断负环. 于是有了一种黑科技: 我们从枚举点 i 開始 dfs .然后扫到点 j 时.保持 i~j 这一条链上的点被标记,然后强行推