HDU HDU - 3416 (单源最短路 + 最大流)

大体题意:

给你一个有向图,告诉你起点S和终点T,要求找出不同的路径来,满足路径是最短路,并且每个路只能用一次!

思路:

方法很巧妙:

可以转换到最大流

先正着求一边单源最短路,在倒着求一边,把在最短路上的边加入到网络中,权值为1,直接求最大流即可!(想一想就知道!)

判断是否在最短路也很简单:

直接看这个边的一个点到S的最短距离和另一个点到T的最短距离之和 加上权值 如果是最短路的话,那么这个边肯定在最短路中了!反之不再!

第一次做 结果超时了 用dinic算法即可!(好水= = )

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000 + 10;
///max flow=====================================
struct Edge{
    int from, to, cap, flow;
    Edge(int from = 0,int to = 0 ,int cap = 0, int flow = 0):from(from),to(to),cap(cap),flow(flow){}
};
struct Dinic{
	int n, m ,s, t;
	vector<Edge> edges;
	vector<int> G[maxn];
	bool vis[maxn];
	int d[maxn];
	int cur[maxn];
	
	void init(int n){
		this->n = n;
		for (int i = 0; i <= n; ++i){
			G[i].clear();
		}
		edges.clear();
	}
	
	void AddEdge(int from,int to, int cap){
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to,from,0,0));
		m = edges.size();
		G[from].push_back(m-2);
		G[to].push_back(m-1);
	}
	
	bool BFS(){
		memset(vis,0,sizeof vis);
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = 1;
		while(!Q.empty()){
			int x = Q.front(); Q.pop();
			for (int i = 0; i < G[x].size(); ++i){
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap > e.flow){
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);	
				}	
			}
		}
		return vis[t];
	}
	int DFS(int x,int a){
		if (x == t || a == 0) return a;
		int flow = 0, f;
		for (int& i = cur[x]; i < G[x].size(); ++i){
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0){
				e.flow += f;
				edges[G[x][i]^1].flow -= f;
				flow += f;
				a-=f;
				if (!a)break;	
			}
		}
		return flow;
	}
	
	int MaxFlow(int s,int t){
		this->s = s; this->t = t;
		int flow = 0;
		while(BFS()){
			memset(cur,0,sizeof cur);
			flow += DFS(s,inf);
		}
		return flow;
	}
}mmf;
///=========================================
/// ====== Dijkstra

struct Edge2{
    int from, to, dist;
    Edge2(int from = 0,int to = 0,int dist = 0):from(from),to(to),dist(dist){}
};
struct HeapNode{
    int d, u;
    HeapNode(int d = 0,int u = 0):d(d),u(u){}
    bool operator < (const HeapNode& rhs) const {
        return d > rhs.d;
    }
};
struct Dijkstra{
    int n, m ;
    vector<Edge2> edges;
    vector<int> G[maxn];
    bool done[maxn];
    int d[maxn];
    int p[maxn];

    void init(int n){
        this->n = n;
        for (int i = 1; i <= n; ++i) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int dist){
        edges.push_back(Edge2(from,to,dist));
        m = edges.size();
        G[from].push_back(m-1);
    }
    void dijkstra(int s){
        priority_queue<HeapNode> Q;
        for (int i = 1; i <= n; ++i) d[i] = inf;
        d[s] = 0;
        memset(done,0,sizeof done);
        Q.push(HeapNode(0,s));
        while(!Q.empty()){
            HeapNode x = Q.top(); Q.pop();
            int u = x.u;
            if (done[u])continue;
            done[u] = 1;
            for (int i = 0; i < G[u].size(); ++i){
                Edge2& e = edges[G[u][i]];
                if (d[e.to] > d[u] + e.dist){
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];
                    Q.push(HeapNode(d[e.to],e.to));
                }
            }
        }
    }
}dijs,dijt;
///==============================================
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n, m;
        scanf("%d %d",&n,&m);
        dijs.init(n);
        dijt.init(n);
        mmf.init(n);
        for (int i = 0; i < m; ++i){
            int u, v, w;
            scanf("%d %d %d",&u, &v, &w);
            dijs.AddEdge(u,v,w);
            dijt.AddEdge(v,u,w);
        }
        int s,t;
        scanf("%d %d",&s,&t);
        dijs.dijkstra(s);
        dijt.dijkstra(t);

        int len = dijs.edges.size();
        for (int i = 0; i < len; ++i){
            int u = dijs.edges[i].from;
            int v = dijs.edges[i].to;
            int w = dijs.edges[i].dist;
            if (dijs.d[u] + dijt.d[v] + w == dijs.d[t]){
                mmf.AddEdge(u,v,1);
            }
        }
        if (dijs.d[t] == inf){
        	printf("0\n");
        	continue;
		}
        int ans = mmf.MaxFlow(s,t);
        printf("%d\n",ans);

    }
    return 0;
}


Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u

 Status

Description

Do not sincere non-interference。 
Like that show, now starvae also take part in a show, but it take place between city A and B. Starvae is in city A and girls are in city B. Every time starvae can get to city B and make a data with a girl he likes. But there are two problems with it, one is starvae must get to B within least time, it's said that he must take a shortest path. Other is no road can be taken more than once. While the city starvae passed away can been taken more than once. 


So, under a good RP, starvae may have many chances to get to city B. But he don't know how many chances at most he can make a data with the girl he likes . Could you help starvae?

Input

The first line is an integer T indicating the case number.(1<=T<=65) 
For each case,there are two integer n and m in the first line ( 2<=n<=1000, 0<=m<=100000 ) ,n is the number of the city and m is the number of the roads. 

Then follows m line ,each line have three integers a,b,c,(1<=a,b<=n,0<c<=1000)it means there is a road from a to b and it's distance is c, while there may have no road from b to a. There may have a road from a to a,but you can ignore it. If there are two roads from a to b, they are different. 

At last is a line with two integer A and B(1<=A,B<=N,A!=B), means the number of city A and city B. 
There may be some blank line between each case.

Output

Output a line with a integer, means the chances starvae can get at most.

Sample Input

3
7 8
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
5 7 1
6 7 1
1 7

6 7
1 2 1
2 3 1
1 3 3
3 4 1
3 5 1
4 6 1
5 6 1
1 6

2 2
1 2 1
1 2 2
1 2

Sample Output

2
1
1

Source

Problem descriptions:
System Crawler 2016-09-12
Initialization.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值