ZOJ 2676 Network Wars(分数规划+最小割)

Network Wars

Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge

Network of Byteland consists of n servers, connected by m optical cables. Each cable connects two servers and can transmitdata in both directions. Two servers of the network are especially important --- they are connected to global world network and president palace network respectively.

The server connected to the president palace network has number 1, and the server connected to the global world network has number n.

Recently the company Max Traffic has decided to takecontrol over some cables so that it could see what data istransmitted by the president palace users. Of course they want to control such set of cables, that it is impossible todownload any data from the global network to the president palacewithout transmitting it over at least one of the cables from the set.

To put its plans into practice the company needs to buy corresponding cables from their current owners. Each cable has somecost. Since the company's main business is not spying, butproviding internet connection to home users, its management wants to make the operation a good investment. So it wants to buy sucha set of cables, that cables mean cost} is minimal possible.

That is, if the company buys k cables of the total cost c, it wants to minimize the value of c/k.

Input

There are several test cases in the input. The first line of each case contains n and m ( 2 <= n <= 100 , 1 <= m <= 400 ). Next m lines describecables~--- each cable is described with three integer numbers:servers it connects and the cost of the cable. Cost of each cableis positive and does not exceed 107 .

Any two servers are connected by at most one cable. Nocable connects a server to itself.The network is guaranteed to be connected, it is possibleto transmit data from any server to any other one.

There is an empty line between each cases.

Output

First output k --- the number of cables to buy. After thatoutput the cables to buy themselves. Cables are numbered startingfrom one in order they are given in the input file.There should an empty line between each cases.

Example

Input Output
6 8
1 2 3
1 3 3
2 4 2
2 5 2
3 4 2
3 5 2
5 6 3
4 6 3
4
3 4 5 6 
4 5
1 2 2
1 3 2
2 3 1
2 4 2
3 4 2
3
1 2 3

Source: Andrew Stankevich's Contest #8

        大致题意:给你一个网络,让你求一个最小割[S,T],使得这个割中Σcapi/|[S,T]|最小。
        论文原题。比较经典的一个分数规划问题。分数规划那些具体的证明什么的今天就不在这里讲了,之后会有总结~ 然后本题还是按照套路。令ans= Σcapi/|[S,T]|,那么可以有0= Σcapi-ans*|[S,T]|,二分这样的一个ans,使得f(x)=min(Σcapi-ans*|[S,T]|)为0即可。问题的关键在于怎么求这个f(x)。
        我们不妨把cap 看作一个向量,表示从1 到m 每一条边的容量,然后设置一个01 向量x ,它的第i 维对应表示第i 条边的取与不取,c=(1,1,...,1)如此一来,f(x)可以表示为f(x)=min((cap-ans*c)*x),拆开成每一条边的形式有f(x)=min(Σ(capi*xi-ans))。这意味着,对于第i条边,如果我选取它,那么它的代价就是capi-ans。现在要求最小的f(x),同时要求答案要至少是一个割,那就相当于把原图中的边权改为capi-ans,求一个最小割即可。
        但是,在执行的过程中,有可能出现capi-ans小于0的情况,由于网络流中不能有负的权值,所以不能建边。但根据取最小的f(x)定义,要把capi-ans加入到f(x)中。之后二分这个x,找到一个使得f(x)等于0的x即可。具体见代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define eps 1e-6
#define M 2010
#define N 110
using namespace std;

struct Edge{int x,y;double w;} g[M];
int n,m; LL sum=0;
bool v[N];

namespace ISAP
{
    int H[N],d[N],cur[N],pre[N],gap[M],Q[M];
    struct Edge{int u,v,n;double c;} E[M];
    int nv,head,tail,cntE; double flow,f;

    void init(){cntE=0; memset(H,-1,sizeof(H));}

    void addedge(int u,int v,double c)
    {
        E[cntE]=Edge{u,v,H[u],c}; H[u]=cntE++;
        E[cntE]=Edge{v,u,H[v],0}; H[v]=cntE++;
    }

    void revbfs(int s,int t)
    {
        head=tail=0 ;
        memset(d,-1,sizeof(d));
        memset(gap,0,sizeof(gap));
        Q[tail++]=t;d[t]=0;gap[d[t]]=1;
        while (head!=tail)
        {
            int u=Q[head++];
            for (int i=H[u];~i;i=E[i].n)
            {
                int v=E[i].v; if (~d[v]) continue;
                d[v]=d[u]+1; gap[d[v]]++; Q[tail++]=v;
            }
        }
    }

    double isap(int s,int t)
    {
        memcpy(cur,H,sizeof(cur)); nv=t;
        flow=0; revbfs(s,t); int u=pre[s]=s,i;
        while (d[s]<nv)
        {
            if (u==t)
            {
                f=INF;
                for (i=s;i!=t;i=E[cur[i]].v)
                    if (f-E[cur[i]].c>eps) f=E[cur[i]].c,u=i;
                flow += f;
                for (i=s;i!=t;i=E[cur[i]].v)
                    E[cur[i]].c-=f,E[cur[i]^1].c+=f;
            }
            for (i=cur[u];~i;i=E[i].n)
                if (fabs(E[i].c)>eps&&d[u]==d[E[i].v]+1) break ;
            if (~i) cur[u]=i,pre[E[i].v]=u,u=E[i].v;
            else
            {
                if (0==--gap[d[u]]) break ;
                int minv=nv,v;
                for (int i=H[u];~i;i=E[i].n)
                {
                    v=E[i].v;
                    if (fabs(E[i].c)>eps&&minv>d[v]) minv=d[v],cur[u]=i;
                }
                d[u]=minv+1; gap[d[u]]++; u=pre[u];
            }
        }
        return flow ;
    }

    void dfs(int x)
    {
        v[x]=1;
        for(int i=H[x];~i;i=E[i].n)
        {
            int to=E[i].v;
            if (v[to]||E[i].c<eps) continue;
            dfs(to);
        }
    }
}


bool check(double x)
{
    using namespace ISAP;
    init();
    double ans=0;
    for(int i=1;i<=m;i++)
        if (g[i].w-x>eps)
        {
            addedge(g[i].x,g[i].y,g[i].w-x);
            addedge(g[i].y,g[i].x,g[i].w-x);
        } else ans+=g[i].w-x;
    ans+=isap(1,n);
    return ans>eps;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        sum=0;
        memset(g,0,sizeof(g));
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            sum+=w;g[i]=Edge{u,v,w};
        }
        double l=0,r=sum,mid;
        while(r-l>eps)
        {
            mid=(r+l)/2.0;
            if (check(mid)) l=mid;
                       else r=mid;
        }
        memset(v,0,sizeof(v));
        ISAP::dfs(1); vector<int> ans;
        for(int i=1;i<=m;i++)
            if (v[g[i].x]+v[g[i].y]==1||g[i].w-mid<eps) ans.push_back(i);
        printf("%d\n",ans.size());
        printf("%d",ans[ans.size()-1]);
        for(int i=0;i<(int)ans.size()-1;i++)
            printf(" %d",ans[i]);
        puts("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/80269353
ZOJ