zoj 3792 最小割等于最大流 Romantic Value

题意:

可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流。最后流量一定等于割边边数

另外:

还有一种求割边的办法。

因为每次我们求出来最大流都是割边的流量,那么,我们可以把原先边的容量×10000+1,那么求出来的最大流/10000不会影响原先的答案,而最大流%10000则是割边的数目

Description

Farmer John is a diligent man. He spent a lot of time building roads between his farms. From his point of view, every road is romantic because the scenery along it is very harmonious and beautiful. Recently, John is immersed in poetry, he wants stay alone and enjoy the wonderful words. But his little brother always disturbs him. This night, fortunately, his little brother does not stay the same farm with him. So, he wants to destroy some roads to keep himself quiet for a few days(then no route exist between John and his brother). Of course, John love his romantic roads, so he want to separate him and his brother with least romantic cost.

There are N farms(numbered from 1 to N) and M undirected roads each with a romantic value c(indicate how much Farmer John loves it). Now John stays in farm p and his little brother stay in farm q. John wants to first minimize the romantic value lost, then to destroy as few roads as possible. Help him to calculate the ratio of [sum of the remainder roads' value]/[the amount of removed roads](not necessary to maximisation this ratio) when he achieves his goal.

Input

The first line is a single integer T, indicate the number of testcases. Then follows T testcase. For each testcase, the first line contains four integers N M p q(you can assume p and q are unequal), then following M lines each contains three integer a b c which means there is an undirected road between farm a and farm b with romantic value c. (2<=N<=50, 0<=M<=1000, 1<=c<1000, 1<=p,q<=N)

Output

For each test case, print the ratio in a single line(keep two decimal places). If p and q exist no route at the start, then output "Inf".

Sample Input

1
4 5 1 4
1 2 1
1 3 1
2 4 2
3 4 2
2 3 1

Sample Output

2.50

第一种是先求完然后再赋值再求顺便第一次用dinic算法

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;

struct node
{
    int v,w,next;
} edge[500000];
int head[5000000],cnt,l[500000],n,m,s,t;
void add(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int bfs()
{
    memset(l,-1,sizeof(l));
    l[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(l[v]==-1&&edge[i].w)
            {
                l[v]=l[u]+1;
                q.push(v);
            }
        }
    }
    return l[t]>0;
}
int dfs(int u,int f)
{
    int a,flow=0;
    if(u==t)
    {
      return f;
    }
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(l[v]==l[u]+1&&edge[i].w&&(a=dfs(v,min(f,edge[i].w))))
        {
           edge[i].w-=a;
           edge[i^1].w+=a;
           flow+=a;
           f-=a;
           if(!f)
            break;
        }
    }
    if(!flow)
        l[u]=-1;
    return flow;
}
int dinic()
{
    int a,ans=0;
    while(bfs())
    {
        while(a=dfs(s,INF))
            ans+=a;
    }
    return ans;
}
int main()
{
    int i,j,u,v,w,T,q,p;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d %d",&n,&m,&p,&q);
        memset(head,-1,sizeof(head));
        cnt=0;
        s=p;
        t=q;
        int sum=0;
        for(i=1;i<=m;i++)
        {
            scanf("%d %d %d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
            sum+=w;
        }
        if(!bfs())
        {
            printf("Inf\n");
            continue;
        }
        int ans=dinic();
        for(int i=0;i<cnt;i+=2)
        {
            if(edge[i].w==0)
                edge[i].w=1;
            else
                edge[i].w=INF;
            edge[i^1].w=0;
        }
        int num=0;
        int a;
        while(bfs())
        {
            while(a=dfs(s,INF))
                num+=a;
        }
        printf("%.2lf\n",(double)(sum-ans)/num);
    }
    return 0;
}
下面是*10000+1的算法,自己写了一份老师WA可能是刚开始学习模版运用还不熟悉有些地方还不懂先贴上开学再来改

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define dou 10000
struct node
{
    int u, v, w, next;
} edge[600000] ;
int head[600000], pre[600000], cur[600000];
int dis[600000],gap[60000],aug[60000];
int s,e,T,cnt,m,n;
void add(int u,int v,int w)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int SAP()
{
    int max_flow = 0, v, u = s;
    int id, mindis;
    aug[s] = INF;
    pre[s] = -1;
    memset(dis, 0, sizeof(dis));
    memset(gap, 0, sizeof(gap));
    gap[0] = T;
    for (int i = 0; i <=T; ++i)
    {
        // 初始化当前弧为第一条弧
        cur[i] = head[i];
    }

    while (dis[s] < T)
    {
        bool flag = false;
        if (u == e)
        {
            max_flow += aug[e];
            for (v = pre[e]; v != -1; v = pre[v]) // 路径回溯更新残留网络
            {
                id = cur[v];
                edge[id].w -= aug[e];
                edge[id^1].w += aug[e];
                aug[v] -= aug[e]; // 修改可增广量,以后会用到
                if (edge[id].w == 0) u = v; // 不回退到源点,仅回退到容量为0的弧的弧尾
            }
        }
        for (id = cur[u]; id != -1; id = edge[id].next)
        {
            // 从当前弧开始查找允许弧
            v = edge[id].v;
            if (edge[id].w > 0 && dis[u] == dis[v] + 1) // 找到允许弧
            {
                flag = true;
                pre[v] = u;
                cur[u] = id;
                aug[v] = min(aug[u], edge[id].w);
                u = v;
                break;
            }
        }
        if (flag == false)
        {
            if (--gap[dis[u]] == 0) break; // gap优化,层次树出现断层则结束算法
            mindis = T;
            cur[u] = head[u];
            for (id = head[u]; id != -1; id = edge[id].next)
            {
                v = edge[id].v;
                if (edge[id].w > 0 && dis[v] < mindis)
                {
                    mindis = dis[v];
                    cur[u] = id; // 修改标号的同时修改当前弧
                }
            }
            dis[u] = mindis + 1;
            gap[dis[u]]++;
            if (u != s) u = pre[u]; // 回溯继续寻找允许弧
        }
    }
    return max_flow;
}
int main()
{
    int i,j,u,v,w,t,q,p;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d %d",&n,&m,&p,&q);
        memset(head,-1,sizeof(head));
        cnt=0;
        s=p;
        e=q;
        T=e+1;
        int all=0;
        for(i=1; i<=m; i++)
        {
            scanf("%d %d %d",&u,&v,&w);
            all+=w;
            add(u,v,w*dou+1);
            add(v,u,w*dou+1);

        }
        int cost=SAP();
        int bian=cost%dou;
        cost=all-cost/dou;
        if(bian==0)
        {
            puts("Inf");
            continue;
        }
        double ans=(double)(cost)/(double)bian;
        printf("%.2lf\n",ans);
    }
    return 0;
}
下面是*10000+1的正确代码是看了别人的

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define init(a) memset(a,0,sizeof(a))
const int N = 210;
const int maxn = 1000;
const int maxm = 5000;
#define MIN INT_MIN
#define MAX 0x3f3f3f3f
#define LL long long
using namespace std;
int max(int a,int b){if(a>b)return a; else return b;}
int min(int a,int b){if(a<b)return a; else return b;}

int n,m;

int head[maxn],bnum;
int dis[maxn];
int num[maxn];
int cur[maxn];
int pre[maxn];
struct node
{
    int v, cap;
    int next;
}edge[maxm];
void add(int u, int v, int cap)
{
    edge[bnum].v=v;
    edge[bnum].cap = cap;
    edge[bnum].next = head[u];
    head[u]=bnum++;

    edge[bnum].v=u;
    edge[bnum].cap=0;
    edge[bnum].next=head[v];
    head[v]=bnum++;
}
void BFS(int source,int sink)
{
    queue<int>q;
    while(q.empty()==false)
        q.pop();
    init(num);
    memset(dis,-1,sizeof(dis));
    q.push(sink);
    dis[sink]=0;
    num[0]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v = edge[i].v;
            if(dis[v] == -1)
            {
                dis[v] = dis[u] + 1;
                num[dis[v]]++;
                q.push(v);
            }
        }
    }
}
LL ISAP(int source,int sink,int n)
{
    memcpy(cur,head,sizeof(cur));

    LL flow=0;
    int  u = pre[source] = source;
    BFS( source,sink);
    while( dis[source] < n )
    {
        if(u == sink)
        {
            int df = MAX, pos;
            for(int i = source;i != sink;i = edge[cur[i]].v)
            {
                if(df > edge[cur[i]].cap)
                {
                    df = edge[cur[i]].cap;
                    pos = i;
                }
            }
            for(int i = source;i != sink;i = edge[cur[i]].v)
            {
                edge[cur[i]].cap -= df;
                edge[cur[i]^1].cap += df;
            }
            flow += df;
            u = pos;
        }
        int st;
        for(st = cur[u];st != -1;st = edge[st].next)
        {
            if(dis[edge[st].v] + 1 == dis[u] && edge[st].cap)
                break;
        }
        if(st != -1)
        {
            cur[u] = st;
            pre[edge[st].v] = u;
            u = edge[st].v;
        }
        else
        {
            if( (--num[dis[u]])==0 ) break;
            int mind = n;
            for(int id = head[u];id != -1;id = edge[id].next)
            {
                if(mind > dis[edge[id].v] && edge[id].cap != 0)
                {
                    cur[u] = id;
                    mind = dis[edge[id].v];
                }
            }
            dis[u] = mind+1;
            num[dis[u]]++;
            if(u!=source)
            u = pre[u];
        }
    }
    return flow;
}
void initt()
{
       memset(head,-1,sizeof(head));
       bnum=0;
}
int main()
{
    int T,N,M,P,Q;
    scanf("%d",&T);
    while(T--)
    {
        initt();
        int u,v,w,sum = 0;
        scanf("%d%d%d%d",&N,&M,&P,&Q);
        for(int i = 1;i<=M;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            sum += w;
            add(u,v,w*10000+1);
            add(v,u,w*10000+1);
        }
       LL ans = ISAP(P,Q,N);
       if(!ans)
       {
           puts("Inf");
           continue;
       }
        int num = ans/10000;
        int num1 = ans%10000;
        //printf("ans = %d num = %d num1 = %d",ans,num,num1);
        printf("%.2lf\n",(double)(sum-num)/num1);
    }
    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值