hdu 1280 Finding shortest path(最短路+最大流最小割)

Finding shortest path
Time Limit: 1000ms
Memory Limit: 65536kb
Description
I guess every contestant knows how to find a shortest path in a bidirectional graph, so this problem is intended to be a bit more difficult than that.

Given a bidirectional graph G=(V,E) with n vertices and m edges, it’s easy to find the shortest path between vertex S and T. Your task is to delete a set of edges with minimum cost, such that the shortest path in new graph is longer than the original one.

Input
The input consists of multiple test cases.

The first line of each test case contains two integers n and m, which specify the number of vertices and edges. (2 ≤ n ≤ 1000, 1 ≤ m ≤ 10000). The second line consists of two integer S and T, indicating the source and the sink. (1 ≤ S,T ≤ nS ≠ T) The next m lines each contains four integers uiviwi and ci, indicating that there’s an edge between vertex ui and vi with length wi, and the cost of deleting it is ci. (1 ≤ ui,vi ≤ n, 0 ≤wi,ci ≤ 1000)

A test case with n=m=0 indicates the end of input.

Output
For each test case, output “ Case  x ” first, where  x  is the case number. Then output the minimum cost to increase the length the shortest path between  S  and  T . The cost is counted as the sum of deleted edges’ cost.

It is guaranteed that shortest path in initial graph always exists, and length of the shortest path between S and T is regarded as infinity if they are not connected.

Sample Input
2 3
1 2
1 2 2 3
1 2 2 4
1 2 3 5
4 5
1 4
1 2 1 1
2 3 1 1
3 4 1 1
1 4 3 2
2 2 2 3
4 5
2 3
1 2 3 2
2 4 3 4
1 3 2 3
3 4 2 3
1 4 0 1
0 0
Sample Output
Case 1: 7
Case 2: 3
Case 3: 6
 
题意:给出一个无向图,给出起点s和终点t,s到t之间存在最短路径,每条边都有各自的花费,若删除某条边,则要付出对应的花费。现在要删除一些边,使得s到t之间的最短路径变长(s与t不连通时最短路径为INF),问最小的花费是多少。
思路:要删除的边一定在s到t的最短路径上,先spfa求一次最短路,然后枚举每条边,若dis[u] + w == dis[v],那么这条边在最短路径上,把这条边加入到网络流中,最后求最小割即可。

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)
using namespace std;

const int maxn = 20005;
const int maxm = 500005;
const int INF = 1000000000;
struct edge{
    int u, v, w, cost, next;
}et1[maxn];
struct Edge{
    int u, v, cap, flow, next;
}et2[maxm];
int eh1[maxn], eh2[maxn], low[maxn], dis1[maxn], dis2[maxn], cnt[maxn], pre[maxn], cur[maxn];
bool vis[maxn];
int n, m, s, t, num1, num2;
void init(){
    memset(eh1, -1, sizeof(eh1));
    memset(eh2, -1, sizeof(eh2));
    num1 = num2 = 0;
}
void add1(int u, int v, int w, int cost){
    edge e = {u, v, w, cost, eh1[u]};
    et1[num1] = e;
    eh1[u] = num1++;
}
void add2(int u, int v, int cap, int flow){
    Edge e = {u, v, cap, flow, eh2[u]};
    et2[num2] = e;
    eh2[u] = num2++;
}
void addedge(int u, int v, int cap){
    add2(u, v, cap, 0);
    add2(v, u, 0, 0);
}
void spfa(){
    queue<int> Q;
    memset(vis, false, sizeof(vis));
    for(int i = 1; i <= n; i++) dis1[i] = INF;
    dis1[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;
        for(int i = eh1[u]; i != -1; i = et1[i].next)
        {
            int v = et1[i].v, w = et1[i].w;
            if(dis1[u] + w < dis1[v])
            {
                dis1[v] = dis1[u] + w;
                if(!vis[v])
                {
                    vis[v] = true;
                    Q.push(v);
                }
            }
        }
    }
}
void build(){
    for(int i = 0; i < num1; i++)
    {
        int u = et1[i].u, v = et1[i].v, w = et1[i].w, cost = et1[i].cost;
        if(dis1[u] + w == dis1[v]) addedge(u, v, cost);
    }
}
int isap(int s, int t, int nv){
    int u, v, now, flow = 0;
    memset(low, 0, sizeof(low));
    memset(cnt, 0, sizeof(cnt));
    memset(dis2, 0, sizeof(dis2));
    for(u = 0; u <= nv; u++) cur[u] = eh2[u];
    low[s] = INF, cnt[0] = nv, u = s;
    while(dis2[s] < nv)
    {
        for(now = cur[u]; now != -1; now = et2[now].next)
        if(et2[now].cap - et2[now].flow && dis2[u] == dis2[v = et2[now].v] + 1) break;
        if(now != -1)
        {
            cur[u] = pre[v] = now;
            low[v] = min(low[u], et2[now].cap - et2[now].flow);
            u = v;
            if(u == t)
            {
                for(; u != s; u = et2[pre[u]].u)
                {
                    et2[pre[u]].flow += low[t];
                    et2[pre[u]^1].flow -= low[t];
                }
                flow += low[t];
                low[s] = INF;
            }
        }
        else
        {
            if(--cnt[dis2[u]] == 0) break;
            dis2[u] = nv, cur[u] = eh2[u];
            for(now = eh2[u]; now != -1; now = et2[now].next)
            if(et2[now].cap - et2[now].flow && dis2[u] > dis2[et2[now].v] + 1)
            dis2[u] = dis2[et2[now].v] + 1;
            cnt[dis2[u]]++;
            if(u != s) u = et2[pre[u]].u;
        }
    }
    return flow;
}
int main()
{
    int u, v, w, c, ca = 0;
    while(scanf("%d%d", &n, &m), n || m)
    {
        init();
        scanf("%d%d", &s, &t);
        while(m--)
        {
            scanf("%d%d%d%d", &u, &v, &w, &c);
            add1(u, v, w, c);
            add1(v, u, w, c);
        }
        spfa();
        build();
        printf("Case %d: %d\n", ++ca, isap(s, t, n + 1));
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值