题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6582

题目大意:有n个点,m条单向带权边,起点为1,终点为n,如果开始没有最短路输出0,现在想堵住一些路,使堵之后的最短路值变大,或不存在。堵路的花费就是边的权值,问最小花费。

思路:找到最短路核心边,再重新建边,跑一遍最小割即可。找最短路核心边要正向建边找每点到起点的距离(假设为d[i]),再反向建边找每点到终点的距离(假设为d2[i]),如果一条边起点为u,终点为v,边权为w,若d[u]+d2[v]+w==d[n]则这是一条最短路核心边。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL maxn=10005;
const LL INF=10000000000000000;
LL d[maxn], cur[maxn], start, tend;
struct node
{
    LL to, cap, next;
} edge[maxn << 1];
LL head[maxn];

LL cnt;
void addedge(LL start, LL to, LL cap)
{
    edge[cnt].to = to;
    edge[cnt].cap = cap;
    edge[cnt].next = head[start];
    head[start] = cnt++;
}
bool BFS()
{
    //memset(vis,false,sizeof(vis));
    memset(d, -1, sizeof(d));
    LL Q[maxn * 2];
    LL Thead, Ttail;
    Thead = Ttail = 0;
    Q[Ttail++] = start;;
    d[start] = 0;
    //vis[start]=1;
    while (Thead<Ttail)
    {
        LL x = Q[Thead];
        if (x == tend)
            return true;
        for (LL i = head[x]; i != -1; i = edge[i].next)
        {
            LL temp = edge[i].to;
            if (d[temp] == -1 && edge[i].cap>0)//没有标记,且可行流大于0
            {
                //vis[temp.to]=true;
                d[temp] = d[x] + 1;
                Q[Ttail++] = temp;
            }
        }
        Thead++;
    }
    return false;//汇点是否成功标号,也就是说是否找到增广路
}
LL DFS(LL x, LL cap)
{
    if (x == tend)
        return cap;
    //vis[start]=true;
    LL flow = 0, f;
    for (LL i = head[x]; i != -1; i = edge[i].next)
    {
        LL temp = edge[i].to;
        //if(temp.cap<=0||vis[temp.to])continue;
        if (d[temp] == d[x] + 1 && edge[i].cap)
        {
            f = DFS(temp, min(cap - flow, edge[i].cap));
            edge[i].cap -= f;
            edge[i ^ 1].cap += f;
            flow += f;
            if (flow == cap)
                break;
        }
    }
    if (!flow)
        d[x] = -2;//防止重搜
    return flow;
}
LL maxflow()
{
    LL flow = 0, f;
    while (BFS())
    {
        //memset(vis,false,sizeof(vis));
        while ((f = DFS(start, INF))>0)
            flow += f;
    }
    return flow;
}

vector< pair<LL ,LL > > e1[maxn], e2[maxn];
LL n, m;
LL dis[maxn];   //dis当前的最短路
LL vis[maxn];   //是否已经求出最短路
LL dis2[maxn];   //dis当前的最短路
LL vis2[maxn];   //是否已经求出最短路
LL xx[maxn], yy[maxn], zz[maxn];

priority_queue<pair<LL, LL> > q;
LL dijkstra(LL s, LL t)
{
    while(!q.empty())
    {
        q.pop();
    }
    dis[s]=0;
    q.push(make_pair(-dis[s], s));
    while(!q.empty())
    {
        LL now=q.top().second;                //一定是最短路上的顶点
        q.pop();
        if(vis[now])
        {
            continue;
        }
        vis[now]=1;
        for(LL i=0;i<e1[now].size();i++)       //访问所有的邻接点
        {
            LL v=e1[now][i].first;
            if(!vis[v]&&dis[v]>dis[now]+e1[now][i].second)
            {
                dis[v]=dis[now]+e1[now][i].second;
                q.push(make_pair(-dis[v], v));//把可能的最短路顶点加入队列
            }
        }
    }
    if(dis[t]==INF)
    {
        return -1;                            //s-t没有通路
    }
    else
    {
        return dis[t];
    }

}

LL dijkstra2(LL s, LL t)
{
    memset(vis, 0 ,sizeof(vis));
    while(!q.empty())
    {
        q.pop();
    }
    dis2[s]=0;
    q.push(make_pair(-dis2[s], s));
    while(!q.empty())
    {
        LL now=q.top().second;                //一定是最短路上的顶点
        q.pop();
        if(vis[now])
        {
            continue;
        }
        vis[now]=1;
        for(LL i=0;i<e2[now].size();i++)       //访问所有的邻接点
        {
            LL v=e2[now][i].first;
            if(!vis[v]&&dis2[v]>dis2[now]+e2[now][i].second)
            {
                dis2[v]=dis2[now]+e2[now][i].second;
                q.push(make_pair(-dis2[v], v));//把可能的最短路顶点加入队列
            }
        }
    }
    if(dis2[t]==INF)
    {
        return -1;                            //s-t没有通路
    }
    else
    {
        return dis2[t];
    }

}

int main()
{
    LL t;
    scanf("%lld",&t);
    while(t--)
    {
        LL n, m;
        scanf("%lld%lld",&n,&m);
        for(LL i=0;i<maxn;i++)   //初始化
        {
            vis[i]=0;
            dis[i]=INF;
            dis2[i]=INF;
            e1[i].clear();
            e2[i].clear();
        }

        for(LL i=0;i<m;i++)
        {
            LL x, y, z;
            scanf("%lld%lld%lld",&x,&y,&z);
            xx[i]=x, yy[i]=y, zz[i]=z;
            e1[x].push_back(make_pair(y ,z));
            e2[y].push_back(make_pair(x ,z));
        }

        dijkstra(1, n);
        dijkstra2(n, 1);

        cnt = 0;
        memset(head, -1, sizeof(head));

        start=1;
        tend=n;

        for(LL i=0; i<=m; i++)
        {
            LL u=xx[i], v=yy[i], w=zz[i];
            if(dis[u]+dis2[v]+w==dis[n])
            {
                addedge(u, v, w);
                addedge(v, u, 0);
            }
        }
        cout<<maxflow()<<endl;

    }
    return 0;
}