sgu176 有源汇上下界最小流

题意:有一堆点和边,1起点,n终点,某些边有可能必须满流,要求满足条件的最小流

解法:按原图建边,满流的即上下界都是容量,但是这样按有源汇上下界可行流求出来的可能不是最小流,那么我们需要开始建边的时候不要建从t到s的边,先跑一边从ss到tt的最大流,然后把该边加上再跑一次从ss到tt的最大流,那么从t到s的反向边流过的流量就是原图的最小流,为什么是这样呢,这是因为当我们第一遍跑最大流的时候,此时没有t到s的这条边,那么图中的流量会尽量按其他的边流,当我们第二次跑最大流的时候,流出来的都是第一次中已经无法流到终点的流量,此时再跑最大流时我们就尽量减少了t到s这条边上的流量,实际上可以看成延迟t到s的增流

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;

const double g=10.0,eps=1e-12;
const int N=100+10,maxn=10000+10,inf=0x3f3f3f3f;

struct edge{
    int from,to,Next,c,low;
}e[maxn<<2];
int cnt,head[N];
int dis[N];
int in[N],out[N];
void add(int u,int v,int c,int low)
{
    out[u]+=low;
    in[v]+=low;
    e[cnt].from=u;
    e[cnt].to=v;
    e[cnt].c=c;
    e[cnt].low=low;
    e[cnt].Next=head[u];
    head[u]=cnt++;
    e[cnt].from=v;
    e[cnt].to=u;
    e[cnt].c=0;
    e[cnt].low=low;
    e[cnt].Next=head[v];
    head[v]=cnt++;
}
bool bfs(int s,int t)
{
    memset(dis,-1,sizeof dis);
    dis[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        if(x==t)return 1;
        for(int i=head[x];~i;i=e[i].Next)
        {
            int te=e[i].to;
            if(dis[te]==-1&&e[i].c>0)
            {
                dis[te]=dis[x]+1;
                q.push(te);
            }
        }
    }
    return 0;
}
int dfs(int x,int mx,int t)
{
    if(x==t)return mx;
    int flow=0;
    for(int i=head[x];~i;i=e[i].Next)
    {
        int te=e[i].to,f;
        if(e[i].c>0&&dis[te]==dis[x]+1&&(f=dfs(te,min(mx-flow,e[i].c),t)))
        {
            e[i].c-=f;
            e[i^1].c+=f;
            flow+=f;
        }
    }
    if(!flow)dis[x]=-2;
    return flow;
}
int maxflow(int s,int t)
{
    int ans=0,f;
    while(bfs(s,t))
    {
        while((f=dfs(s,inf,t)))ans+=f;
    }
    return ans;
}
void init()
{
    cnt=0;
    memset(head,-1,sizeof head);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    while(cin>>n>>m)
    {
        init();
        int s=1,t=n;
        for(int i=1;i<=m;i++)
        {
            int a,b,c,d;
            cin>>a>>b>>c>>d;
            if(d)add(a,b,0,c);
            else add(a,b,c,0);
        }
        int ss=n+1,tt=n+2;
        int sum=0;
        for(int i=1;i<=n;i++)
        {
          //  cout<<in[i]<<" "<<out[i]<<endl;
            if(in[i]>out[i])sum+=in[i]-out[i],add(ss,i,in[i]-out[i],0);
            else add(i,tt,out[i]-in[i],0);
        }
        int flow=maxflow(ss,tt);
        add(t,s,inf,0);
        flow+=maxflow(ss,tt);
        if(sum!=flow)cout<<"Impossible"<<endl;
        else
        {
            cout<<e[cnt-1].c<<endl;
            for(int i=0;i<2*m;i+=2)
                cout<<e[i^1].c+e[i].low<<" ";
            cout<<endl;
        }
    }
    return 0;
}
/********************

********************/

时间: 2024-10-21 13:25:22

sgu176 有源汇上下界最小流的相关文章

hdu3157有源汇上下界最小流

题意:有源汇上下界最小流裸题,主要就是输入要用字符串的问题 #include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 10000000

[hdu] 3157 Crazy Circuits || 有源汇上下界最小流

原题 有两个正负极n个节点和m个元件,每个元件告诉端点是接在哪个节点上的,并且每个元件有工作的最小电流限制,问使所有元件工作的满足条件的最小电流是多少. 有源汇上下界最小流. 考虑dinic的推流思想,所以在跑完可行流后,减去t到s的最大流就是最小流. 实现方法: 建图时先不加入t到s的inf边,跑最大流,再加入inf边跑最大流.若此刻是可行流,那么加入的t到s的inf边的反向边的权值就是最小流. ll ans=0; ans+=dinic(); add(t,s,inf); ans+=dinic(

HDU 3157 Crazy Circuits(有源汇上下界最小流)

HDU 3157 Crazy Circuits 题目链接 题意:一个电路板,上面有N个接线柱(标号1~N),还有两个电源接线柱 + -,给出一些线路,每个线路有一个下限值求一个可以让所有部件正常工作的总电流 没有则输出impossible 思路: 有源汇有上下界求最小流,建模方法为: 按无源汇先建图,跑超级源汇ss->tt一次,然后加入t->s,容量INF的边,在跑一次ss->tt,如果是满流,就有解,解为t->s边的当前流量 顺带写个最大流的,最大流就先把t->s加入直接跑

BZOJ_2502_清理雪道_有源汇上下界最小流

Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部.从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道. 由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务. Input 输入文件的第一行包含一个整数n (2

bzoj 2502 清理雪道 (有源汇上下界最小流)

2502: 清理雪道 Time Limit: 10 Sec  Memory Limit: 128 MB Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部.从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道. 由于每次飞行的耗费是固定的,为了最小化耗费

算法复习——有源汇上下界可行流(bzoj2396)

题目: Description We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, so

POJ2396&amp;ZOJ1994--Budget【有源汇上下界可行流】

链接:http://poj.org/problem?id=2396 题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息. 思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样. 建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一

zoj 3229 Shoot the Bullet(有源汇上下界最大流)

Shoot the Bullethttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 Time Limit: 2 Seconds      Memory Limit: 32768 KB      Special Judge Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utopia

有源汇上下界可行流(POJ2396)

题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流即可. 具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流. 然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边. 如果那些容量为l的边没满流,则无解. #include <cstdio> #incl