【题解】洛谷P3953[NOIP2017]逛公园 最短路+拓扑排序+计数类DP

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


学习了大佬题解。根据大佬的讲解,把对应部分分的代码打到一起了。(有点臃肿)

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1e5+10,M=2e5+10;
#define re register
int tot,t,n,m,k,p,hd[N],vis[N],hdn[N],totn,id[N],idx[N];
int cnt[N],f[N][55],ans,deg[N],hd0[N],tot0,q[N];
ll dis[N],disn[N];
inline int read()
{
	int s=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
	return s*f;
}
struct Edge{
	int v,nx;ll w;
}e[M],en[M];
struct node{
	int u;ll w;
	node(){}
	node(int _u,ll _w):u(_u),w(_w){}
	bool operator <(const node&rhs)const{
	return w>rhs.w;}
};
namespace pts30{
	void add(int u,int v,ll w)
    {
	    e[tot].v=v;
	    e[tot].nx=hd[u];
	    e[tot].w=w;
	    hd[u]=tot++;
    }
	void dijkstra()
	{
		memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
		priority_queue<node>q;dis[1]=0;q.push(node(1,0));cnt[1]=1;
		while(q.size())
		{
			int u=q.top().u;q.pop();vis[u]=0;
			for(int i=hd[u];~i;i=e[i].nx)
			{
				int v=e[i].v;
				if(dis[v]>dis[u]+e[i].w)
				{
					dis[v]=dis[u]+e[i].w;cnt[v]=cnt[u];
					if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
				}
				else if(dis[v]==dis[u]+e[i].w)
				{
					cnt[v]+=cnt[u];
					if(cnt[v]>=p)cnt[v]-=p;
				}
			}
		}
		printf("%d\n",cnt[n]%p);
	}
	void solve()
	{
		using namespace pts30;
		t=read();
	    while(t--)
	    {
		    memset(hd,-1,sizeof(hd));tot=0;
		    n=read();m=read();k=read();p=read();
	        int u,v;ll w;
	        for(int i=1;i<=m;i++)
	            u=read(),v=read(),w=read(),add(u,v,w);
	        dijkstra();
        }
	}
}
namespace pts70{
	inline void add(int u,int v,ll w)
    {
	    e[tot].v=v;
	    e[tot].nx=hd[u];
	    e[tot].w=w;
	    hd[u]=tot++;
    }
    bool cmp(const int &a,const int &b)
    {
    	return dis[a]<dis[b];
	}
    void dijkstra()
	{
		memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
		priority_queue<node>q;dis[1]=0;q.push(node(1,0));
		while(q.size())
		{
			int u=q.top().u;q.pop();vis[u]=0;
			for(int i=hd[u];~i;i=e[i].nx)
			{
				int v=e[i].v;
				if(dis[v]>dis[u]+e[i].w)
				{
					dis[v]=dis[u]+e[i].w;
					if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
				}
			}
		}
	}
	void solve()
	{
		using namespace pts70;
		t=read();
	    while(t--)
	    {
		    memset(hd,-1,sizeof(hd));tot=0;
		    memset(hdn,-1,sizeof(hdn));totn=0;
		    memset(f,0,sizeof(f));ans=0;
		    n=read();m=read();k=read();p=read();
	        int u,v;ll w;
	        for(int i=1;i<=m;i++)
	            u=read(),v=read(),w=read(),add(u,v,w);
            dijkstra();
            for(int i=1;i<=n;i++)id[i]=i;
            sort(id+1,id+n+1,pts70::cmp);
            f[1][0]=1;
			for(int j=0;j<=k;j++)
				for(int i=1;i<=n;i++)
            	{
            		int u=id[i];
            		for(int o=hd[u];~o;o=e[o].nx)
            		{
            			int v=e[o].v;ll w=e[o].w;
            			if(dis[u]+j+w-dis[v]<=k)
            			{
            				f[v][dis[u]+j+w-dis[v]]+=f[u][j];
							if(f[v][dis[u]+j+w-dis[v]]>=p)f[v][dis[u]+j+w-dis[v]]-=p;
						}
					}
				}
			for(int j=0;j<=k;j++)
			{
				ans+=f[n][j];if(ans>=p)ans-=p;
			}
			printf("%d\n",ans);
		}
	}
}
namespace AC{
	struct Edge0{
		int v,nx;
	}e0[M];
	inline void add(int u,int v,ll w)
    {
	    e[tot].v=v;
	    e[tot].nx=hd[u];
	    e[tot].w=w;
	    hd[u]=tot++;
    }
	inline void addn(int u,int v,ll w)
    {
	    en[totn].v=v;
	    en[totn].nx=hdn[u];
	    en[totn].w=w;
	    hdn[u]=totn++;
    }
    inline void add0(int u,int v)
    {
    	e0[tot0].v=v;
    	e0[tot0].nx=hd0[u];
    	hd0[u]=tot0++;
	}
	inline void dijkstran()
	{
		memset(disn,0x7f,sizeof(disn));memset(vis,0,sizeof(vis));
		priority_queue<node>q;disn[1]=0;q.push(node(1,0));
		while(q.size())
		{
			re int u=q.top().u;q.pop();vis[u]=0;
			for(re int i=hdn[u];~i;i=en[i].nx)
			{
				re int v=en[i].v;
				if(disn[v]>disn[u]+en[i].w)
				{
					disn[v]=disn[u]+en[i].w;
					if(!vis[v])vis[v]=1,q.push(node(v,disn[v]));
				}
			}
		}
	}
	inline void dijkstra()
	{
		memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis));
		priority_queue<node>q;dis[1]=0;q.push(node(1,0));
		while(q.size())
		{
			re int u=q.top().u;q.pop();vis[u]=0;
			for(re int i=hd[u];~i;i=e[i].nx)
			{
				re int v=e[i].v;
				if(dis[v]>dis[u]+e[i].w)
				{
					dis[v]=dis[u]+e[i].w;
					if(!vis[v])vis[v]=1,q.push(node(v,dis[v]));
				}
			}
		}
	}
	bool toposort()
	{
		re int h=1,t=0;
		for(re int i=1;i<=n;i++)
		    if(!deg[i])q[++t]=i;
		while(h<=t)
		{
			re int u=q[h++];
			for(re int i=hd0[u];~i;i=e0[i].nx)
			{
				re int v=e0[i].v;
				if(--deg[v]==0)q[++t]=v;
			}
		}
		for(re int i=1;i<=n;i++)id[q[i]]=i;
		for(re int i=1;i<=n;i++)
		    if(deg[i]&&dis[i]+disn[i]-dis[n]<=k)return true;
		return false;
	}
	inline bool cmp(const int &a,const int &b)
    {
    	return dis[a]<dis[b]||(dis[a]==dis[b]&&id[a]<id[b]);
	}
	inline void solve()
	{
		using namespace AC;
		t=read();
	    while(t--)
	    {
		    memset(hd,-1,sizeof(hd));tot=0;
		    memset(hdn,-1,sizeof(hdn));totn=0;
		    memset(hd0,-1,sizeof(hd0));tot0=0;
		    memset(deg,0,sizeof(deg));memset(f,0,sizeof(f));ans=0;
			n=read();m=read();k=read();p=read();
	        int u,v,w;
	        for(re int i=1;i<=m;i++)
	        {
	        	u=read();v=read();w=read();add(u,v,w);addn(v,u,w);
	        	if(!w)add0(u,v),deg[v]++;
			}
			dijkstra();dijkstran();
			if(toposort()){puts("-1");continue;}
			f[1][0]=1;
			for(re int i=1;i<=n;i++)idx[i]=i;sort(idx+1,idx+n+1,cmp);
			for(re int j=0;j<=k;j++)
			    for(re int i=1;i<=n;i++)
			    {
			    	re int u=idx[i];
			    	for(re int o=hd[u];~o;o=e[o].nx)
			    	{
			    		re int v=e[o].v;ll w=e[o].w;
			    		if(dis[u]+w+j-dis[v]<=k)
			    		{
			    			f[v][dis[u]+w+j-dis[v]]+=f[u][j];
			    			if(f[v][dis[u]+w+j-dis[v]]>=p)f[v][dis[u]+w+j-dis[v]]-=p;
						}
					}
				}
			for(re int i=0;i<=k;i++)
			{
				ans+=f[n][i];
				if(ans>=p)ans-=p;
			}
			printf("%d\n",ans);
        }
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
	//pts30::solve();
	//pts70::solve();
	AC::solve();
	return 0;
}

总结

首先看到路径数,想能不能DP转移,然后通过求出的最短路按照拓扑序进行转移,还得判断0环。

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/82963466