ZOJ 2676 分数规划

zoj 2676 过了 sap的问题,准备找个好点的sap板子

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define eps 1e-5
#define maxn 500
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 110;
const double esp = 1e-8;
int sign(double x){ return x<-esp?-1:(x>esp);}
int n, m, Max;
int S, N, T;
bool inde[maxn];

 struct node
    {
        int u,v,cost;
    }in[maxn];


struct Edge{
    int u, v, nxt;
    double f;
}edge[50101];
struct Edge_Info{
    int a,b,c;
    void input(){
        scanf("%d%d%d",&a,&b,&c);
    }
}edge_info[550];
bool vis[MAXN];
int h[MAXN], vh[MAXN];
int head[MAXN], idx;

void AddEdge(int a,int b,double f){
    edge[idx].u = a, edge[idx].v = b, edge[idx].f = f;
    edge[idx].nxt = head[a], head[a] = idx++;
    edge[idx].u = b, edge[idx].v = a, edge[idx].f = 0;
    edge[idx].nxt = head[b], head[b] = idx++;
}

double dfs(int u,double flow){
    if(u == T) return flow;
    int tmp = h[u]+1; double sum = flow;
    for(int i = head[u]; ~i; i = edge[i].nxt){
        if( sign(edge[i].f) > 0 && (h[ edge[i].v ]+1 == h[u])){
            double p = dfs( edge[i].v, min(sum,edge[i].f));
            edge[i].f -= p, edge[i^1].f += p, sum -= p;
            if( sign(sum)==0 || h[S]==N ) return flow-sum;
        }
    }
    for(int i = head[u]; ~i; i = edge[i].nxt ){
        if( sign(edge[i].f) > 0 ) tmp = min(tmp,h[ edge[i].v ] );
    }
    if( --vh[ h[u] ] == 0 ) h[S] = N;
    else ++vh[ h[u]=tmp+1 ];
    return flow-sum;
}
double sap(){
    double maxflow = 0;
    memset(h,0,sizeof(h));
    memset(vh,0,sizeof(vh));
    vh[0] = N;
    while( h[S] < N ) maxflow += dfs( S,inf );
    return maxflow;
}

void DFS(int u){
    vis[u] = true;
    for(int i = head[u]; ~i; i = edge[i].nxt){
        if( sign(edge[i].f) > 0 && !vis[ edge[i].v ] )
            DFS( edge[i].v );
    }
}


    void dfs(int u)
    {
        vis[u] = 1;
        for(int i = head[u];i != -1;i = edge[i].nxt)
        {
          if( sign(edge[i].f) > 0 && !vis[ edge[i].v ] )
            dfs( edge[i].v );
        }
    }

    double build(double g)
    {
     memset( head, -1, sizeof(head));
    idx = 0;
        double all=0;

        for(int i=1;i<=m;i++)
        {
            double temp=in[i].cost*1.0-g;
            if( sign(temp) <0 )
                all+=temp;
            else
            AddEdge(in[i].u,in[i].v,temp),AddEdge(in[i].v,in[i].u,temp);

        }
        return all;
    }

    bool judge(double mid)
    {
        double temp=build(mid);
        double res=sap();
        res+=temp;
        if(res<eps) return true;
        else return false;
    }

    void output(double ans)
    {
    int a[maxn];
    memset(inde,false,sizeof(inde));
   memset( head, -1, sizeof(head));
    idx = 0;
        for(int i=1;i<=m;i++)
        {
            double temp=in[i].cost*1.0-ans;
            if( sign(temp) <0 )
                inde[i]=true;
             else  AddEdge(in[i].u,in[i].v,temp),AddEdge(in[i].v,in[i].u,temp);

        }
    memset(vis,0,sizeof(vis));
    sap();
    dfs(1);
    int counter=0;
    for(int i=1;i<=m;i++)
    {
        int tempa=in[i].u;
        int tempb=in[i].v;
        if((vis[tempa]&&!vis[tempb])||(!vis[tempa]&&vis[tempb]))
            inde[i]=true;
    }
    for(int i=1;i<=m;i++)
        if(inde[i])
        a[++counter]=i;
    printf("%d\n",counter);
    for(int i=1;i<counter;i++)
        printf("%d ",a[i]);
    printf("%d\n\n",a[counter]);
    }



    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
           S=1;T=n;N=n;
            int ma=0;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d%d",&in[i].u,&in[i].v,&in[i].cost);
                if(in[i].cost>ma) ma=in[i].cost;
            }
            double left=0;
            double right=ma*1.0;
            while(right-left>eps)
            {
                double mid=(left+right)*0.5;
                if(judge(mid))
                    right=mid;
                else left=mid;
            }
            output(left);
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值