您的位置:首页 > 理论基础 > 计算机网络

Marriage Match IV HDU3461 网络流+最短路spfa

2017-07-20 11:26 267 查看


Marriage Match IV

 

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

题解:

本题目的实质就是最短路径计数,但是有一点需要强调的一点就是,这里的边不能重复走,否则的话,跑完spfa,一遍dfs就ok了。

在这里要求边不能走重复,所以说,我们就要用网络流的方法来做了。重点是怎么建图。

我们先用spfa求一下起点到所有点的最短路。

然后进行dfs建边,建边的时候,但d[v] == d[u] + cost的时候,表明这条边有可能构成最短路的一条路径,那么就从u向v连接一条容量为1的边。

(这里千万要注意的一点就是,走过的边要打标记,不要重复走,否则会陷入死循环)

边建立完成以后,跑一个从起点到终点的网络流就好了

代码:

#include<cstdio>
#include<iostream>
#include <cstring>
#include <queue>
using namespace std;
const int oo=1e9;
/**oo 表示无穷大*/
const int mm=200007;
/**mm 表示边的最大数量,记住要是原图的两倍,在加边的时候都是双向的*/
const int mn=1007;
/**mn 表示点的最大数量*/
int node,src,dest,edge;
/**node 表示节点数,src 表示源点,dest 表示汇点,edge 统计边数*/
int ver[mm],flow[mm],nxt[mm];
/**ver 边指向的节点,flow 边的容量,nxt 链表的下一条边*/
int head[mn],work[mn],dis[mn],q[mn];
/**head 节点的链表头,work 用于算法中的临时链表头,dis 计算距离*/

/**初始化链表及图的信息*/
void prepare(int _node,int _src,int _dest)
{
node=_node,src=_src,dest=_dest;
memset(head,-1,sizeof(head));
edge=0;
}
/**增加一条u 到v 容量为c 的边*/
void addedge(int u,int v,int c)
{
ver[edge]=v,flow[edge]=c,nxt[edge]=head[u],head[u]=edge++;
ver[edge]=u,flow[edge]=0,nxt[edge]=head[v],head[v]=edge++;
}
/**广搜计算出每个点与源点的最短距离,如果不能到达汇点说明算法结束*/
bool Dinic_bfs()
{
int i,u,v,l,r=0;
for(i=0; i<node; ++i)dis[i]=-1;
dis[q[r++]=src]=0;
for(l=0; l<r; ++l)
for(i=head[u=q[l]]; i>=0; i=nxt[i])
if(flow[i]&&dis[v=ver[i]]<0)
{
/**这条边必须有剩余容量*/
dis[q[r++]=v]=dis[u]+1;
if(v==dest)return 1;
}
return 0;
}
/**寻找可行流的增广路算法,按节点的距离来找,加快速度*/
int Dinic_dfs(int u,int exp)
{
if(u==dest)return exp;
/**work 是临时链表头,这里用i 引用它,这样寻找过的边不再寻找*/
for(int &i=work[u],v,tmp; i>=0; i=nxt[i])
if(flow[i]&&dis[v=ver[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
{
flow[i]-=tmp;
flow[i^1]+=tmp;
/**正反向边容量改变*/
return tmp;
}
return 0;
}
int Dinic_flow()
{
int i,ret=0,delta;
while(Dinic_bfs())
{
for(i=0; i<node; ++i)work[i]=head[i];
while(delta=Dinic_dfs(src,oo))ret+=delta;
}
return ret;
}
const int MAXN = 1007;
int heads[MAXN];
int cnt;
struct edge{
int v;
int nxt;
int cost;
}Es[200007];
int d[MAXN];
void init(){
cnt = 0;
memset(heads,-1,sizeof(heads));
}
inline void add_edge(int i,int j,int cost){
Es[cnt].v = j;
Es[cnt].cost = cost;
Es[cnt].nxt = heads[i];
heads[i] = cnt++;
}
void spfa(int x){
memset(d,0x3f,sizeof(d));
int instack[MAXN];
memset(instack,0,sizeof(instack));
d[x] = 0;
queue<int> Q;
Q.push(x);
instack[x] = 1;
while(!Q.empty()){
int u = Q.front();Q.pop();
for(int e = heads[u];e != -1;e = Es[e].nxt){
int v = Es[e].v;
int cost = Es[e].cost;
if(d[v] > d[u] + cost){
d[v] = d[u] + cost;
if(!instack[v]){
instack[v] = 1;
Q.push(v);
}
}
}
instack[u] = 0;
}
}
int visit[200007];
void dfs(int x){
for(int e = heads[x];e != -1;e = Es[e].nxt){
int v = Es[e].v;
if(d[v] == d[x] + Es[e].cost){
if(!visit[e]){
visit[e] = 1;
addedge(x-1,v-1,1);
dfs(v);
}
}
}
}

int main(){
int T;
scanf("%d",&T);
while(T--){
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a == b) continue;
add_edge(a,b,c);
}
int beg,tar;
scanf("%d%d",&beg,&tar);
prepare(n,beg-1,tar-1);
spfa(beg);
memset(visit,0,sizeof(visit));
dfs(beg);
int ans = Dinic_flow();
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流 最短路 计数