HDU - 3416 - Marriage Match IV(网络流+最短路Dij)

题目:HDU-3416

题意:有t组数据,n个点,m条边的图。从s走到t点,只走最短距离,每条路只能走一次。问走最短路总共有多少种方案

题解:先用最短路算法求出从起点到各点的距离dist,然后根据dist的值建立新的图,边权为1,套用Dinic模板求起点到终点的最大流即可。但是这里最短路算法最好用SPFA遍历所有边才好,如果用Dij+优先队列需要把vis[i]的访问标记删掉,因为这是求从s到x的最短路有多少条,如果用Dij的话只要求到最小值就好了,所以有可能会漏了某些边,所以要删去vis标记部分

代码:

#include<bits/stdc++.h>
#define N 1005
#define M 100505
#define INF 0x3f3f3f3f
using namespace std;
int T,n,m,s,t,c,c1;
int head[N],head1[N],dis[N],deep[N],cur[N];
bool vis[N];
struct ljh
{
	int next,to,w;
}e[2*M],a[2*M];
struct xqy
{
	int x,d;
	xqy(int x=0,int d=0):x(x),d(x){}
	bool operator < (const xqy&a) const
	{
		return a.d<d;
	}
};
inline void add(int x,int y,int z)
{
	e[c].next=head[x];
	e[c].to=y;
	e[c].w=z;	
	head[x]=c++;
}
inline void add1(int x,int y,int z)
{
	a[c1].next=head1[x];
	a[c1].to=y;
	a[c1].w=z;
	head1[x]=c1++;
}
void Dij(int s)
{
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)dis[i]=INF;
	priority_queue<xqy>q;
	dis[s]=0;
	q.push(xqy(s,0));
	while(!q.empty())
	{
		xqy now=q.top();
		q.pop();
		int x=now.x;
		// if(vis[x])continue;
		// vis[x]=1;
        //要把这个删去,否则一直WA到自闭
		for(int i=head[x];i!=-1;i=e[i].next)
		{
			int nex=e[i].to;
			if(dis[nex]>dis[x]+e[i].w)
			{
				dis[nex]=dis[x]+e[i].w;
				q.push(xqy(nex,dis[nex]));
			}
		}
	}
	return;
}
bool bfs(int s,int t)
{
	queue<int>q;
	memset(deep,0,sizeof(deep));
	deep[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		for(int i=head1[x];i!=-1;i=a[i].next)
		{
			int nex=a[i].to;
			if(deep[nex]==0&&a[i].w>0)
			{
				deep[nex]=deep[x]+1;
				q.push(nex);
			}
		}
	}
	return deep[t]!=0;
}
int dfs(int x,int t,int maxflow)
{
	if(x==t)return maxflow;
	int ans=0;
	for(int i=head1[x];i!=-1;i=a[i].next)
	{
		int nex=a[i].to;
		if(deep[nex]!=deep[x]+1||a[i].w<=0||ans>=maxflow)continue;
		cur[x]=i;
		int k=dfs(nex,t,min(a[i].w,maxflow-ans));
		a[i].w-=k;
		a[i^1].w+=k;
		ans+=k;
	}
	if(ans==0)deep[x]=-2;
	return ans;
}
int Dinic(int s,int t)
{
	int ans=0;
	while(bfs(s,t))
	{
		memcpy(cur,head1,sizeof(head1));
		ans+=dfs(s,t,INF);
	}
	return ans;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		c=0;
		c1=0;
		memset(head,-1,sizeof(head));
		memset(head1,-1,sizeof(head1));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			if(x==y)continue;
			add(x,y,z);
		}
		scanf("%d%d",&s,&t);
		Dij(s);
		for(int i=1;i<=n;i++)
		{
			for(int j=head[i];j!=-1;j=e[j].next)
			{
				if(dis[e[j].to]==dis[i]+e[j].w)
				{
					add1(i,e[j].to,1);
					add1(e[j].to,i,0);
				}
			}
		}
		printf("%d\n",Dinic(s,t));
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值