【SGU 176】 Flow construction

176. Flow construction

time limit per test: 0.5 sec.

memory limit per test: 4096 KB

input: standard

output: standard

You have given the net consisting of nodes and pipes; pipes connect the nodes. Some substance can flow by pipes, and flow speed in any pipe doesn’t exceed capacity of this pipe.

The substance cannot be accumulated in the nodes. But it is being produced in the first node with the non-negative speed and being consumed with the same speed in the last node.

You have some subset taken from the set of pipes of this net. You need to start the motion of substance in the net, and your motion must fully fill the pipes of the given subset. Speed of the producing substance in the first node must be minimal.

Calculate this speed and show the scene of substance motion.

Remember that substance can’t be accumulated in the nodes of the net.

Input

Two positive integer numbers N (1<=N<=100) and M have been written in the first line of the input - numbers of nodes and pipes.

There are M lines follows: each line contains four integer numbers Ui, Vi, Zi, Ci; the numbers are separated by a space. Ui is the beginning of i-th pipe, Vi is its end, Zi is a capacity of i-th pipe (1<=Zi<=10^5) and Ci is 1 if i-th pipe must be fully filled, and 0 otherwise.

Any pair of nodes can be connected only by one pipe. If there is a pipe from node A to node B, then there is no pipe from B to A. Not a single node is connected with itself.

There is no pipe which connects nodes number 1 and N. Substance can flow only from the beginning of a pipe to its end.

Output

Write one integer number in the first line of the output - it ought to be the minimal speed of the producing substance in the first node.

Write M integers in the second line - i-th number ought to be the flow speed in the i-th pipe (numbering of pipes is equal to the input).

If it is impossible to fill the given subset, write “Impossible”.

Sample test(s)

Input

Input 1:

4 4

1 2 2 0

2 4 1 1

1 3 2 1

3 4 3 0

Input 2:

4 4

1 2 1 0

2 4 2 1

1 3 3 1

3 4 2 0

Output

Output 1:

3

1 1 2 2

Output 2:

Impossible

有源汇有上下界的最小流。

详见《有上下界的网络流问题

二分法:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#define M 20005
#define inf 0x3f3f3f3f
using namespace std;
int h[M],s,jud,t,cur[M],tot,d[M],id[M],v[M],n,m,down[M];
struct edge
{
    int from,to,cap,flow,ne;
}E[M];
void Addedge(int from,int to,int cap)
{
    E[++tot]=(edge){from,to,cap,0,h[from]};
    h[from]=tot;
    E[++tot]=(edge){to,from,0,0,h[to]};
    h[to]=tot;
}
int bfs()
{
    for (int i=s;i<=t;i++)
        v[i]=0;
    queue<int> q;
    q.push(s);
    v[s]=1;
    d[s]=0;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=h[x];i;i=E[i].ne)
        {
            edge e=E[i];
            if (!v[e.to]&&e.cap>e.flow)
            {
                v[e.to]=1;
                d[e.to]=d[x]+1;
                q.push(e.to);
            }
        }
    }
    return v[t];
}
int dfs(int x,int a)
{
    if (x==t||!a) return a;
    int flow=0;
    for (int &i=cur[x];i;i=E[i].ne)
    {
        edge &e=E[i];
        if (d[e.to]!=d[x]+1) continue;
        int f=dfs(e.to,min(e.cap-e.flow,a));
        if (f>0)
        {
            flow+=f;
            a-=f;
            e.flow+=f;
            E[i^1].flow-=f;
            if (!a) break;
        }
    }
    return flow;
}
int dinic()
{
    int flow=0;
    while (bfs())
    {
        for (int i=s;i<=t;i++)
            cur[i]=h[i];
        flow+=dfs(s,inf);
    }
    return flow;
}
int ok()
{
    return jud==dinic();
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
    jud=0;
    s=0,t=n+1;
    tot=1;
    for (int i=s;i<=t;i++)
        h[i]=0;
    for (int i=1;i<=m;i++)
    {
        id[i]=0;
        int x,y,z,c;
        scanf("%d%d%d%d",&x,&y,&z,&c);
        if (c) down[i]=z,jud+=z,Addedge(s,y,z),Addedge(x,t,z);
        else down[i]=0,Addedge(x,y,z),id[i]=tot-1;
    }
    int l=0,r=inf,ans=inf;
    Addedge(n,1,0);
    while (l<=r)
    {
        for (int i=0;i<=tot;i++)
            E[i].flow=0;
        int mid=(l+r)>>1;
        E[tot-1].cap=mid;
        if (ok()) ans=mid,r=mid-1;
        else l=mid+1;
    }
    if (ans==inf) puts("Impossible");
    else
    {
        for (int i=0;i<=tot;i++)
            E[i].flow=0;
        E[tot-1].cap=ans;
        dinic();
        printf("%d\n",ans);
        for (int i=1;i<=m;i++)
            printf("%d%c",E[id[i]].flow+down[i],i==m?‘\n‘:‘ ‘);
    }
    }
    return 0;
}

效率高的做法:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#define M 20005
#define inf 0x3f3f3f3f
using namespace std;
int h[M],s,jud,t,cur[M],tot,d[M],id[M],v[M],n,m,down[M];
struct edge
{
    int from,to,cap,flow,ne;
}E[M];
void Addedge(int from,int to,int cap)
{
    E[++tot]=(edge){from,to,cap,0,h[from]};
    h[from]=tot;
    E[++tot]=(edge){to,from,0,0,h[to]};
    h[to]=tot;
}
int bfs()
{
    for (int i=s;i<=t;i++)
        v[i]=0;
    queue<int> q;
    q.push(s);
    v[s]=1;
    d[s]=0;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=h[x];i;i=E[i].ne)
        {
            edge e=E[i];
            if (!v[e.to]&&e.cap>e.flow)
            {
                v[e.to]=1;
                d[e.to]=d[x]+1;
                q.push(e.to);
            }
        }
    }
    return v[t];
}
int dfs(int x,int a)
{
    if (x==t||!a) return a;
    int flow=0;
    for (int &i=cur[x];i;i=E[i].ne)
    {
        edge &e=E[i];
        if (d[e.to]!=d[x]+1) continue;
        int f=dfs(e.to,min(e.cap-e.flow,a));
        if (f>0)
        {
            flow+=f;
            a-=f;
            e.flow+=f;
            E[i^1].flow-=f;
            if (!a) break;
        }
    }
    return flow;
}
int dinic()
{
    int flow=0;
    while (bfs())
    {
        for (int i=s;i<=t;i++)
            cur[i]=h[i];
        flow+=dfs(s,inf);
    }
    return flow;
}
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
    jud=0;
    s=0,t=n+1;
    tot=1;
    for (int i=s;i<=t;i++)
        h[i]=0;
    for (int i=1;i<=m;i++)
    {
        id[i]=0;
        int x,y,z,c;
        scanf("%d%d%d%d",&x,&y,&z,&c);
        if (c) down[i]=z,jud+=z,Addedge(s,y,z),Addedge(x,t,z);
        else down[i]=0,Addedge(x,y,z),id[i]=tot-1;
    }
    int flow=dinic();
    Addedge(n,1,inf);
    flow+=dinic();
    if (flow!=jud) puts("Impossible");
    else
    {
        dinic();
        printf("%d\n",E[tot-1].flow);
        for (int i=1;i<=m;i++)
            printf("%d%c",E[id[i]].flow+down[i],i==m?‘\n‘:‘ ‘);
    }
    }
    return 0;
}
时间: 2024-10-14 21:35:52

【SGU 176】 Flow construction的相关文章

【四边形不等式】HDU3516-Tree Construction

[题目大意] 给定n个点(x,y),并且保证xi<xj&&yi>yj当i<j.要求建一颗树,树的边只能向上和向右生长,求将所有点都连起来树的长度最小. [思路] 定义状态 dp[i,j]表示点i到点j合并在一起的最小花费(树枝的长度).如dp[3,4]表示图中绿色的这一段. 状态转移方程:dp[i,j]= min(dp[i,k]+dp[k+1,j]+w(i,j) ) i<k<j,w(i,j)=py[k]-py[j]+px[k+1]-px[i]. [注意点] 初

【SGU 390】Tickets (数位DP)

Tickets Description Conductor is quite a boring profession, as all you have to do is just to sell tickets to the passengers. So no wonder that once upon a time in a faraway galaxy one conductor decided to diversify this occupation. Now this conductor

【Codeforces 675D】Tree Construction

[链接] 我是链接,点我呀:) [题意] 依次序将数字插入到排序二叉树当中 问你每个数字它的父亲节点上的数字是啥 [题解] 按次序处理每一个数字 对于数字x 找到最小的大于x的数字所在的位置i 显然,x要放在这个x的左子树里面 所以如果x的左子树为空那么直接放上去就好 否则,左子树不为空的话,对于i的左儿子,从这个左儿子开始,一直往右儿子方向往下走 即未插入x之前,最大的且比i对应的数字小的数字 less 我们的x显然是要放在less的右子树上才行. 这个less和位置i对应的数字都能用java

【SGU 194】 Reactor Cooling

194. Reactor Cooling time limit per test: 0.5 sec. memory limit per test: 65536 KB input: standard output: standard The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuclear reactor to produce plutonium for t

【SGU 180】Inversions —— 归并排序或树形数组计算逆序对

原题链接 180. Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: standard There are N integers (1<=N<=65537) A1, A2,.. AN (0<=Ai<=10^9). You need to find amount of such pairs (i, j) that 1<=i<j&l

Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法

/** 题目:Flow construction SGU - 176 链接:https://vjudge.net/problem/SGU-176 题意: 有源汇有上下界的最小流. 给定n个点,m个管道.每个管道给出u,v,z,c.u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z. 如果c==0,表示没有下界. 求从1到n的最小流. 思路: 第一种做法: 转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于

sgu 176 Flow construction(有源汇的上下界最小流)

[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足流量平衡的最小流量. [思路] 按照可行流构造网络.不连t->s的边先跑一遍附加源汇点的最大流,然后连t->s一条inf边,在残量网络上跑一遍最大流.第一次求最大流所以能走的边都已经流满,第二次求附加源汇点最大流t->s的流量就会尽可能小. 另外还可以二分下界mid,然后连边(T,S,mid

sgu Flow construction

Flow construction 题目: 给出N个节点M条水管,要求在满足上下界的情况下.满足起点最小的流量. 算法: 这是最小流????不知道.只知道用求解上下界最大流的方法就过了. 做这题收获了很多东西.知道了同一点的flow是真实的流量值,虽然以前在书上或论文中看到过,不过印象不深,但是经过这题深刻的懂了.就是这题输出的时候有点麻烦...要记录每次的路径,然后用我刚才说的那个,同一个点的flow是真实的流量值!!!! #include <iostream> #include <a

2014 HDU多校弟五场J题 【矩阵乘积】

题意很简单,就是两个大矩阵相乘,然后求乘积. 用 Strassen算法 的话,当N的规模达到100左右就会StackOverFlow了 况且输入的数据范围可达到800,如果变量还不用全局变量的话连内存开辟都开不出来 1 #pragma comment(linker, "/STACK:16777216") 2 #include <iostream> 3 #include <stdio.h> 4 #define ll long long 5 using namesp