[FZOJ1570]&&[2014-10-28 模拟赛] 花园的守护之神 (greendam.*)

描述 Description

看着正在被上古神兽们摧残的花园,花园的守护之神――小 Bug 同学泪流满面。然而,FZOI 不相信眼泪,小 bug 与神兽们的战争将进行到底!

通过 google,小 Bug 得知,神兽们来自遥远的戈壁。为了扭转战局,小 Bug 决定拖延神兽增援的速度。从戈壁到达花园的路径错综复杂,由若干段双向的小路组成。神兽们通过每段小路都需要一段时间。小 Bug 可以通过向其中的一些小路投掷小 xie 来拖延神兽。她可以向任意小路投掷小 Xie,而且可以在同一段小路上投掷多只小 xie。每只小 Xie 可以拖延神兽一个单位的时间。即神兽通过整段路程的总时间,等于没有小 xie 时他们通过同样路径的时间加上路上经过的所有小路上的小 xie 数目总和。

神兽们是很聪明的。他们会在出发前侦查到每一段小路上的小 Xie 数目,然后选择总时间最短的路径。小 Bug 现在很想知道最少需要多少只小 Xie,才能使得神兽从戈壁来到花园的时间变长。作为花园中可爱的花朵,你能帮助她吗?

输入格式 InputFormat

第 1 行包括一个整数 N,表示地图中路点的个数;一个整数 M,表示小路个数;以及整数 S 和 T,分别表示戈壁和花园的路点编号。N 个路点分别被编号为自然数 1~N。
以下 M 行, 每行三个整数 A、B 和 C,表示路点 A 和 B 之间有一条小路相连,且通过它需要的时间为 C。
输入数据保证两路点间最多只有一条小路相连,且戈壁和花园的路点是连通的。

输出格式 OutputFormat

一个整数,表示使 S 到 T 之间最短路增长所需要的最少的小 xie 的数目。

样例输入 SampleInput

6 11 2 5
2 3 1
2 1 4
2 6 2
5 4 11
5 1 16
5 6 18
4 1 5
4 6 7
3 1 3
3 6 1
1 6 2

样例输出 SampleOutput

3


FZOJ 1570


代码 Code

按照最短路建图,求最小割。

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int inf=0x7fffffff/27.11;
int i,j,t,n,m,l,r,k,z,y,x;
int S,T,cnt,ans;
struct edge
{
    int to,next,val;
}e[4995005],fe[4995005];
int head[1005],dis[1005];
int fhead[1005],fdis[1005],last[1005];;
bool used[1005];
deque <int> q,fq;
inline void read(int &x)
{
    x=0;char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}
inline void insert(int u,int v,int w)
{
    e[++cnt].to=v;e[cnt].next=head[u];e[cnt].val=w;
    head[u]=cnt;
}
inline void finsert(int u,int v,int w)
{
    fe[++cnt].to=v;fe[cnt].next=fhead[u];fe[cnt].val=w;
    fhead[u]=cnt;
}
inline void spfa(int s)
{
    int i,j,t,u,v,w;
    memset(used,false,sizeof(used));
    for (i=1;i<=n;i++) dis[i]=inf;
    while (!q.empty()) q.pop_front();
    q.push_back(s);dis[s]=0;used[s]=true;
    while (!q.empty())
    {
        u=q.front();q.pop_front();used[u]=false;
        for (i=head[u];i;i=e[i].next)
        {
            v=e[i].to;w=e[i].val+k;
            if (dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if (!used[v])
                {
                    used[v]=true;
                    if (!q.empty() && dis[v]<dis[q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
}
inline void build()
{
    int i,j,t,u,v,w;
    cnt=1;
    for (i=1;i<=n;i++) for (j=head[i];j;j=e[j].next) if (dis[i]+e[j].val==dis[e[j].to])
    {
        finsert(i,e[j].to,1);
        finsert(e[j].to,i,0);
    }
}
inline bool bfs(int s)
{
    int i,j,t,u,v,w;
    while (!fq.empty()) fq.pop_front();
    memset(fdis,-1,sizeof(fdis));
    fdis[s]=0;fq.push_back(s);
    while (!fq.empty())
    {
        u=fq.front();fq.pop_front();
        for (i=fhead[u];i;i=fe[i].next)
        {
            v=fe[i].to;
            if (fe[i].val && fdis[v]==-1)
            {
                fdis[v]=fdis[u]+1;
                fq.push_back(v);
            }
        }
    }
    return (fdis[T]!=-1);
}
inline int find(int s,int low)
{
    int i,j,t,f;
    f=t=0;
    if (s==T) return low;
    for (i=(last[s])?last[s]:fhead[s];i;i=fe[i].next)
    {
        last[s]=i;
        if (fe[i].val>0 && fdis[s]+1==fdis[fe[i].to] && (t=find(fe[i].to,min(low,fe[i].val))))
        {
            fe[i].val-=t;
            fe[i^1].val+=t;
            low-=t;
            f+=t;
            if (low==0) break;
        }
    }
    return f;
}
inline void dinic()
{
    ans=0;
    build();
    while (bfs(S))
    {
        memset(last,0,sizeof(last));
        ans+=find(S,inf);
    }
}
int main()
{
    cnt=0;
    read(n);read(m);read(S);read(T);
    for (i=1;i<=m;i++)
    {
        read(x);read(y);read(z);
        insert(x,y,z);
        insert(y,x,z);
    }
    spfa(S);
    dinic();
    printf("%d\n",ans);
    return 0;
}