UVA 10917

     这道题的意思是,起点是1,终点是2,从1走到2,对于一条边(a,b),只有当存在一条从b出发的到2的路径长小于任何从a出发的路径长,我们才能走,问走到2的方案数。首先我们考虑,如果存在一条b出发的路径,那一定是b到2的最短路,而从a出发到2的路径的最小值也是a到2的最短路,那么我们可以以2为起点做一遍最短路,然后我们枚举边,如果对于一条边(u,v),dis[u]>dis[v],我们就在新图中加入u-->v,可以知道新图是一个DAG,因为如果成环的话,我们可以推出矛盾,这样我们在DAG上DP算方案数即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1005
#define maxm 200005
int last[maxn][2],pre[maxm][2],other[maxm][2],len[maxm][2];
int dis[maxn],n,m,l,que[maxm+5],rd[maxn],dp[maxn];
bool vis[maxn];

void connect(int x,int y,int z,int opt)
{
	l++;
	pre[l][opt]=last[x][opt];
	last[x][opt]=l;
	other[l][opt]=y;
	len[l][opt]=z;	
}

void spfa(void)
{
	int h=0,t=1;
	que[1]=2;
	while (h!=t) 
	{
		h=h%maxm+1;
		int u=que[h];vis[u]=0;
		for (int p=last[u][0];p;p=pre[p][0]) 
		{
			int v=other[p][0];
			if (dis[v]>dis[u]+len[p][0]) 
			{
				dis[v]=dis[u]+len[p][0];
				if (!vis[v]) 
				{
					t=t%maxm+1;
					que[t]=v;
					vis[v]=1;	
				}
			}
		}
	}
}

int main()
{
	while (1) 
	{
		scanf("%d",&n);
		if (n==0) break;
		scanf("%d",&m);
		memset(last,0,sizeof last);l=0;
		memset(dis,127,sizeof dis);dis[2]=0;
		memset(dp,0,sizeof dp);
		memset(rd,0,sizeof rd);
		for (int i=1;i<=m;i++) 
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			connect(a,b,c,0);
			connect(b,a,c,0);
		}
		spfa();
		for (int i=1;i<=n;i++) 
			for (int p=last[i][0];p;p=pre[p][0]) 
			{
				int v=other[p][0];
				if (dis[v]<dis[i]) 
				{
					connect(i,v,0,1);	
					rd[v]++;
				}
			}
		int h=1,t=0;
		for (int i=1;i<=n;i++) 
			if (rd[i]==0) que[++t]=i;
		while (h<=t) 
		{
			int u=que[h];h++;
			for (int p=last[u][1];p;p=pre[p][1]) 
			{
				int v=other[p][1];
				rd[v]--;
				if (rd[v]==0) que[++t]=v;
			}
		}
		dp[2]=1;
		for (int i=n;i>=1;i--) 
		{
			int u=que[i];
			for (int p=last[u][1];p;p=pre[p][1]) 
			{
				int v=other[p][1];
				dp[u]+=dp[v];
			}
		}
		printf("%d\n",dp[1]);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值