2019 Multi-University Training Contest 1--Path--hdu--6582

Path

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2034    Accepted Submission(s): 555

 

Problem Description

Years later, Jerry fell in love with a girl, and he often walks for a long time to pay visits to her. But, because he spends too much time with his girlfriend, Tom feels neglected and wants to prevent him from visiting her.
After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n. 
Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl's home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer.
Note, if Jerry can't reach his girl's house in the very beginning, the answer is obviously zero. And you don't need to guarantee that there still exists a way from Jerry's house to his girl's after blocking some edges.

Input

The input begins with a line containing one integer T(1≤T≤10), the number of test cases.
Each test case starts with a line containing two numbers n,m(1≤n,m≤10000), the number of houses and the number of one-way roads in the neighbourhood.
m lines follow, each of which consists of three integers x,y,c(1≤x,y≤n,1≤c≤109), denoting that there exists a one-way road from the house indexed x to y of length c.

Output

Print T lines, each line containing a integer, the answer.

Sample Input

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

Sample Output

3

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=6582

题意:

给你一个有n个点,m条边的有向图。让你以最小的代价删除一些边使得从点1到点n的最短路变长,删掉一条边的代价为这条边的长度,不连通也算长度增加,也不用考虑删完之后点1是否能到达点n。

题解:

首先由于从1到n的最短路可能存在多条,所以需要先把所有最短路上的边拎出来建一张图G;
然后在图G上跑最小割,用最小的花费把源点1和汇点n割开,割开之后原图中所有原有最短路必然不联通,此时1~n的最短路长度必然增加;
因为“最小割=最大流”定理,所以只需要在图G上跑最大流算法即可。


如何建立图G呢?
这相当于要找出从1到n的所有最短路。
如果在dijkstra中用vector记录每个节点的多个前驱节点(或边),有可能会MLE;
怎么办呢?
观察每一条边,如果其存在于从1到n的最短路上,那么满足式子:
dist[u]+cost[i]+dist2[v]==dist[n],
其中dist[j]是从1到j的最短路,cost[i]是第i条边的权值,dist2[j]是从j到n的最短路;
dist2是通过反向建图跑dijkstra得到的。
为了防止TLE,这里使用Heap+Dijkstra。


Dinic由于采用分层图、多路增广等策略,时间复杂度比其他网络流算法较优,其时间复杂度是O(n^2*m);
算起来仍然TLE,但网络流算法时间复杂度很奇怪,Dinic跑的很快,加上当前弧优化之后交就是了!

代码:

#include <bits/stdc++.h>
#define Pii pair<int,int>
using namespace std;
typedef long long llong;
const llong inf=1e16;
const int tmax=1e4+5,inf_int=1e9+5;
struct node {
    llong d;
    int x;
    bool operator<(const node &b)const
    {
        return d>b.d;
    }
};
int n,m,xx[tmax],yy[tmax],cc[tmax];
vector<Pii> GG[tmax];
priority_queue<node> Q;
bool vis[tmax];
llong dis[tmax],_dis[tmax];
void dijk(int s,llong *d)
{
    int i,u,v,w,len;
    node tmp;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++) d[i]=inf;
    d[s]=0;
    Q.push((node){0,s});
    while(!Q.empty())
    {
        tmp=Q.top();
        Q.pop();
        u=tmp.x;
        if(vis[u]) continue;
        vis[u]=true;
        len=GG[u].size();
        for(i=0;i<len;i++)
        {
            v=GG[u][i].first;
            w=GG[u][i].second;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                Q.push((node){d[v],v});
            }
        }
    }
    return;
}
struct edge{
    int to,cap,rev;
};
vector<edge> G[tmax];
int level[tmax]; 
int iter[tmax];  
void add(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
    return;
}
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=0;i<G[v].size();i++)
        {
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
    return;
}
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v];i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int Dinic(int s,int t)
{
    int flow=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,inf_int))>0)
            flow+=f;
    }
}
int main()
{
    int TT,i;
    scanf("%d",&TT);
    while(TT--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&xx[i],&yy[i],&cc[i]);
            GG[xx[i]].push_back(Pii(yy[i],cc[i]));
        }
        dijk(1,dis);
        for(i=1;i<=n;i++)
            GG[i].clear();
        for(i=1;i<=m;i++)
            GG[yy[i]].push_back(Pii(xx[i],cc[i]));
        dijk(n,_dis);
        for(i=1;i<=m;i++)
        {
            if(dis[xx[i]]+cc[i]+_dis[yy[i]]==dis[n])
                add(xx[i],yy[i],cc[i]);
        }
        cout<<Dinic(1,n)<<endl;
        for(i=1;i<=n;i++)
        {
            GG[i].clear();
            G[i].clear();
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值