HDU 3599(最短路上最大流)

本文探讨了一个结合最短路径算法与最大流算法的解决方案,用于求解特定类型的图论问题。通过先使用Dijkstra算法找到两点间的所有最短路径,再基于这些路径构建网络并运行最大流算法,最终得出从起点到终点的不含重复边的路径数量。文章详细介绍了算法的实现过程,包括数据结构设计、关键步骤和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
n给顶点,最多1e6条无向边(为什么是1e6,因为wa了一发又一发后试出来的 ),问从1到n的不含重复边的短路有多少条。

思路:
先跑dijkstra跑出最短路,然后挑选出满足最短路径上的边建边,跑最大流即可。

注意:TLE可能是因为边数组开小了,别问我为什么知道 还有n=1的时候答案为0

AC code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1500 + 100;
const int maxm = 1000050;
const int INF = 0x3f3f3f3f;
struct Dij{
    struct Edge{
        int to,next;
        int w;
    }edge[maxm << 1];
    int n,m,tot;
    int head[maxn];
    bool vis[maxn];
    void init(int N){
        tot = 0;
        this->n = N;
        for(int i = 0; i <= N; ++i) head[i] = -1;
    }
    struct node{
        int id;
        int dis;
        node(){};
        node(int iid,int dd):id(iid),dis(dd){};
        bool operator < (const node &d) const{
            return dis > d.dis;
        }
    }d[maxn];
    inline void addedge(int u,int v,int w){
        edge[tot] = (Edge){v,head[u],w}, head[u] = tot++;
    }
    void dijkstra(int s,int t){
        for(int i = 0; i <= n; ++i){
            d[i].dis = INF, d[i].id = i, vis[i] = 0;
        }
        priority_queue<node>q;
        d[s].dis = 0;
        q.push(d[s]);
        while(!q.empty()){
            int u = q.top().id; q.pop();
            if(vis[u]) continue ;
            vis[u] = 1;
            for(int i = head[u]; ~i; i = edge[i].next){
                int v = edge[i].to;
                //if(vis[v]) continue ;
                if(d[v].dis > d[u].dis + edge[i].w){
                    d[v].dis = d[u].dis + edge[i].w;
                    q.push(d[v]);
                }
            }
        }
        return ;
    }
}D;

#define captype int
struct SAP{
    struct Edge{
        int from,to,next;
        captype cap;
    }edge[maxm];
    int tot,head[maxn];
    int dis[maxn],cur[maxn],pre[maxn],gap[maxn];
    void init(int n){
        tot = 0;
        //memset(head,-1,sizeof(head));
        for(int i = 0; i <= n; ++i) head[i] = -1;
    }
    inline void addedge(int u,int v,captype c,captype rc = 0){
        edge[tot] = (Edge){u,v,head[u],c}, head[u] = tot++;
        edge[tot] = (Edge){v,u,head[v],rc}, head[v] = tot++;
    }
    captype max_flow(int s,int t,int n){ //包括源点和汇点在内的总点数
        for(int i = 0; i < maxn; ++i){
            gap[i] = dis[i] = 0;
            cur[i] = head[i];
        }
        pre[s] = -1, gap[s] = n;
        captype ans = 0;
        int u = s;
        while(dis[s] < n){
            if(u == t){
                captype minn = INF;
                int v;
                for(int i = pre[u]; ~i; i = pre[edge[i^1].to]){
                    if(minn > edge[i].cap){
                        minn = edge[i].cap, v = i;
                    }
                }
                for(int i = pre[u]; ~i; i = pre[edge[i^1].to]){
                    edge[i].cap -= minn;
                    edge[i^1].cap += minn;
                }
                ans += minn;
                u = edge[v^1].to;
                continue ;
            }
            bool ok = 0;
            int v;
            for(int i = cur[u]; ~i; i = edge[i].next){
                v = edge[i].to;
                if(edge[i].cap > 0 && dis[u] == dis[v] + 1){
                    ok = 1, cur[u] = pre[v] = i;
                    break ;
                }
            }
            if(ok){
                u = v; continue ;
            }
            int mind = n;
            for(int i = head[u]; ~i; i = edge[i].next){
                if(edge[i].cap > 0 && mind > dis[edge[i].to]){
                    mind = dis[edge[i].to];
                    cur[u] = i;
                }
            }
            --gap[dis[u]];
            if(!gap[dis[u]]) return ans;
            dis[u] = mind + 1;
            ++gap[dis[u]];
            if(u != s) u = edge[pre[u]^1].to;
        }
        return ans;
    }
}F;

int a[1000050],b[1000050],c[1000050];
bool vis[1550];
int main(){
    int n,T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        D.init(n);
        int m = 0;
        while(1){
            scanf("%d%d%d",&a[m],&b[m],&c[m]);
            if(a[m] ==0 && b[m] == 0 && c[m] == 0) break ;
            D.addedge(a[m],b[m],c[m]);
            D.addedge(b[m],a[m],c[m]);
            ++m;
        }
        D.dijkstra(1,n);
        if(n == 1 || D.d[n].dis == INF){
            puts("0");
            continue ;
        }
        F.init(n);
        int u,v;
        int s = 0, t = n + 1;
        F.addedge(s,1,INF);
        F.addedge(n,t,INF);
        for(int i = 0; i <= n; ++i) vis[i] = 0;
        for(int i = 0; i < m; ++i){
            u = a[i], v = b[i];
            if(D.d[u].dis > D.d[v].dis) swap(u,v);
            if(D.d[v].dis - D.d[u].dis == c[i]){
                F.addedge(u,v,1);
                vis[u] = vis[v] = 1;
            }
        }
        int cnt = 2;
        for(int i = 1; i <= n; ++i) if(vis[i]) ++cnt;
        printf("%d\n",F.max_flow(s,t,cnt));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值