hdu3416(SAP网络流)

思路:这天显然是要求从最短路走,然后就是问在边不重复走的情况下,有多少条从源点到汇点的路径,由于边不重复,所以就是每条边的可行流量为1,接下来就是网络流的问题了。但是由于开始不会SAP只会写DINIC,所以TLE了一天,最后学了下下SAP,,,勉强给过了这题,,,大哭还是太弱了QWQ!!!

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof a)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
inline int Readint(){
	char c = getchar();
	while(!isdigit(c)) c = getchar();
	int x = 0;
	while(isdigit(c)){
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x;
}
const int maxm = 333333;
const int maxn = 2222;
struct node{
	int v,cost;
};
vector<node> G[maxn];
struct Edge{
	int v,cap,nxt;
}E[maxm];
int head[maxn];
int cur[maxn];
int pre[maxn];
int lev[maxn];
int gap[maxn];
int NV,cnt,n,m,vs,vt;
int dist[maxn];
bool visit[maxn];
void Add(int u,int v,int c){
	E[cnt].v = v;E[cnt].cap = c;E[cnt].nxt = head[u];head[u] = cnt++;
	E[cnt].v = u;E[cnt].cap = 0;E[cnt].nxt = head[v];head[v] = cnt++;
}
void SPFA(){
	memset(dist, INF,sizeof dist);
	memset(visit, false,sizeof visit);
	dist[vs] = 0;
	queue<int> que;
	que.push(vs);
	while(!que.empty()){
		int u = que.front();
		que.pop();
		visit[u] = false;
		for (int i = G[u].size() - 1;i >= 0;--i){
			int v = G[u][i].v;
			int w = G[u][i].cost;
			if (dist[v] > dist[u] + w){
				dist[v] = dist[u] + w;
				if (!visit[v]){
					visit[v] = true;
					que.push(v);
				}
			}
		}
	}
}

int SAP(int vs,int vt){
	memset(lev, 0,sizeof lev);
	memset(pre, -1,sizeof pre);
	memset(gap, 0,sizeof gap);
	// memcpy(cur, head,sizeof head);
	for (int i = 1;i <= n;++i) cur[i] = head[i];
	int u = pre[vs] = vs;
	int maxflow = 0,aug = -1;
	gap[0] = NV;
	while(lev[vs] < NV){
loop:
		for (int &i = cur[u];i != -1;i = E[i].nxt){
			int v = E[i].v;
			if (E[i].cap && lev[u] == lev[v] + 1){
				aug == -1?(aug = E[i].cap):(aug = min(aug,E[i].cap));
				pre[v] = u;
				u = v;
				if (v == vt){
					maxflow += aug;
					for (u = pre[v];v != vs;v = u,u = pre[u]){
						E[cur[u]].cap -= aug;
						E[cur[u] ^ 1].cap += aug;
					}
					aug = -1;
				}
				goto loop;
			}
		}
		int minlev = NV;
		for (int i = head[u];i != -1;i = E[i].nxt){
			int v = E[i].v;
			if (E[i].cap && minlev > lev[v]){
				cur[u] = i;//保存当前弧
				minlev = lev[v];
			}
		}
		if (--gap[lev[u]] == 0) break;
		/*更新gap数组后如果出现断层,则直接退出*/
		lev[u] = minlev + 1;/*重新更新标号*/
		gap[lev[u]]++;/*距离标号为lev[u]的点的个数+1*/
		u = pre[u];/*转当前点的前驱节点继续寻找可行弧*/
	}
	return maxflow;
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int t;
	int u,v,d;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for (int i = 1;i <= n;i++)
			G[i].clear();
		for (int i = 1;i <= m;i++){
			scanf("%d%d%d",&u,&v,&d);
			if (u == v) continue;
			node p;
			p.v = v;
			p.cost = d;
			G[u].push_back(p);
		}
		scanf("%d%d",&vs,&vt);
		SPFA();
		cnt = 0;
		NV = n;
		memset(head, -1,sizeof head);
		for (int i = 1;i <= n;i++){
			for (int j = 0;j < G[i].size();++j){
				if (dist[G[i][j].v] == dist[i] + G[i][j].cost)
					Add(i,G[i][j].v,1);
			}
		}
		printf("%d\n",SAP(vs,vt));
	}
	return 0;
}


你可能感兴趣的:(SAP,图论,网络流)