现在的位置: 首页 > 综合 > 正文

模拟赛 最小乘积路

2018年04月24日 ⁄ 综合 ⁄ 共 3961字 ⁄ 字号 评论关闭

题目描述

给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径。

输入格式

第一行读入两个整数n,m,表示共n个点m条边。

接下来m行,每行三个正整数x,y,z,表示点x到点y有一条边权为z的边。

输出格式

输出仅包括一行,记为所求路径的边权之积,由于答案可能很大,因此输出它模9987的余数即可。

样例数据 1

输入  [复制]

3 3 
1 2 3 
2 3 3 
1 3 10

输出

9

备注

对于20%的数据,n<=10。

对于100%的数据,n<=1000,m<=1000000。边权不超过10000。

题解

一道很简单的最短路,取个对数并记录路径即可。

方案一:spfa+SLF优化,话说感觉spfa好写。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MAXN 1000002
#define mod 9987
#define inf 1<<30
using namespace std;
int n,m,zz,head[1002];
struct bian {int frm,to,nx,v;double c;} e[MAXN];
double dis[1002];
int pd[1002],from[1002],q[1002];
void insert(int x,int y,int z)
{
	zz++; e[zz].frm=x; e[zz].to=y;
	e[zz].v=z; e[zz].c=log(z);
	e[zz].nx=head[x]; head[x]=zz;
}
void init()
{
	scanf("%d%d",&n,&m);
	int i,x,y,z;
	for(i=1;i<=m;i++)
	   {scanf("%d%d%d",&x,&y,&z);
	    insert(x,y,z);
	   }
}
void spfa()
{
	int i,t=0,w=1,x,p;
	for(i=1;i<=n;i++) dis[i]=inf;
	q[t]=1; dis[1]=0; pd[1]=1;
	while(t!=w)
	   {x=q[t]; t=(t+1)%1000;
	    for(i=head[x];i;i=e[i].nx)
		   {p=e[i].to;
		    if(dis[p]>dis[x]+e[i].c)
		       {dis[p]=dis[x]+e[i].c;
		        from[p]=i;
			    if(!pd[p])
			       {if(dis[p]<=dis[q[t]])
				       {t=(t+1000-1)%1000; q[t]=p; pd[p]=1;}
				    else
				       {q[w]=p; pd[p]=1; w=(w+1)%1000;}
				   }
			   }
		   }
		pd[x]=0;
	   }
	i=from[n];
	ll ans=1;
	while(i!=0)
	   {ans=(ans*e[i].v)%mod;
	    i=from[e[i].frm];
	   }
	printf("%lld\n",ans);
}
int main()
{
	init(); spfa();
	return 0;
}

方案二:spfa+堆,话说只是因为感觉这种算法会快一点点,好像实际上也没有快多少,有些点更慢了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MAXN 1000002
#define mod 9987
#define inf 1<<30
using namespace std;
int n,m,zz,head[1002];
struct bian {int frm,to,nx,v;double c;} e[MAXN];
double dis[1002];
int pd[1002],from[1002],q[1002],size;
void insert(int x,int y,int z)
{
	zz++; e[zz].frm=x; e[zz].to=y;
	e[zz].v=z; e[zz].c=log(z);
	e[zz].nx=head[x]; head[x]=zz;
}
void init()
{
	scanf("%d%d",&n,&m);
	int i,x,y,z;
	for(i=1;i<=m;i++)
	   {scanf("%d%d%d",&x,&y,&z);
	    insert(x,y,z);
	   }
}
void heapfy(int w)
{
	int l=w<<1,r=l+1,minw=w;
	if(l<=size&&dis[q[l]]<dis[q[w]]) minw=l;
	if(r<=size&&dis[q[r]]<dis[q[minw]]) minw=r;
	if(minw!=w)
	   {swap(q[w],q[minw]); heapfy(minw);}
}
void del()
{
	q[1]=q[size]; size--;
	if(size) heapfy(1);
}
void weih(int w)
{
	while(w>1)
	   {int i=w>>1;
	    if(dis[q[w]]<dis[q[i]]) swap(q[w],q[i]);
	    w=w>>1;
	   }
}
void spfa()
{
	int i,x,p;
	for(i=1;i<=n;i++) dis[i]=inf;
	q[1]=1; dis[1]=0; pd[1]=1; size=1;
	while(size>0)
	   {x=q[1]; del();
	    for(i=head[x];i;i=e[i].nx)
		   {p=e[i].to;
		    if(dis[p]>dis[x]+e[i].c)
		       {dis[p]=dis[x]+e[i].c;
		        from[p]=i;
			    if(!pd[p])
			       {q[++size]=p; pd[p]=1; weih(size);}
			   }
		   }
		pd[x]=0;
	   }
	i=from[n];
	ll ans=1;
	while(i!=0)
	   {ans=(ans*e[i].v)%mod;
	    i=from[e[i].frm];
	   }
	printf("%lld\n",ans);
}
int main()
{
	init(); spfa();
	return 0;
}

方案三:dijkstra+堆,话说我不会用STL库的东西(太难记了),所以我的代码是手写堆,很长。比以上两种方法快了不少。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define mod 9987
using namespace std;
int n,m,zz,head[1002];
struct bian
{int frm,to,nx,v; double c;} e[1000002];
struct dui{double d;int w;} q[10002];
int pd[1002],size,from[1002];
double dis[1002];
//-----------------------------------------------------------------------------
int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}
void insert(int x,int y,int z)
{
	zz++; e[zz].to=y; e[zz].frm=x;
	e[zz].v=z; e[zz].c=log(z);
	e[zz].nx=head[x]; head[x]=zz;
}
void init()
{
	n=read(); m=read();
	int i,x,y,z;
	for(i=1;i<=m;i++)
	   {x=read(); y=read(); z=read();
	    insert(x,y,z);
	   }
}
void heapfy(int x)
{
	int l=x<<1,r=l+1,minx=x;
	if(l<=size&&q[l].d<q[x].d) minx=l;
	if(r<=size&&q[r].d<q[minx].d) minx=r;
	if(minx!=x)
	   {swap(q[minx],q[x]); heapfy(minx);}
}
void del()
{
	q[1]=q[size]; size--;
	if(size) heapfy(1);
}
void weih(int x)
{
	if(x<=1) return;
	int i=x>>1;
	if(q[i].d>q[x].d) swap(q[i],q[x]);
	weih(i);
}
void dijkstra()
{
	int i,x,p;
	for(i=1;i<=n;i++) dis[i]=1e10;
	size=1; q[1].d=log(1); q[1].w=1; dis[1]=0;
	while(size)
	   {x=q[1].w; del();
	    if(pd[x]) continue;
	    pd[x]=1;
	    for(i=head[x];i;i=e[i].nx)
	       {p=e[i].to;
			if(dis[p]>dis[x]+e[i].c)
			   {dis[p]=dis[x]+e[i].c;
				from[p]=i;
			    size++; q[size].d=dis[p]; q[size].w=p; weih(size);
			   }
		   }
	   }
	ll ans=1;
	for(i=from[n];i;i=from[e[i].frm])
	   ans=(ans*e[i].v)%mod;
	printf("%lld\n",ans);
}
int main()
{
	init(); dijkstra();
	return 0;
}

抱歉!评论已关闭.