zoukankan      html  css  js  c++  java
  • LG3953 逛公园

    题意

    策策同学特别喜欢逛公园。公园可以看成一张(N)个点(M)条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,(N)号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

    策策每天都会去逛公园,他总是从(1)号点进去,从(N)号点出来。

    策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果(1)号点 到(N)号点的最短路长为(d),那么策策只会喜欢长度不超过(d+K)的路线。

    策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

    为避免输出过大,答案对(P)取模。

    如果有无穷多条合法的路线,请输出(-1)

    (N leq 100000,M leq 200000,K leq 50)

    分析

    考虑dp。用(f(x,lim))表示从x到n的路径长不超过dis(x,n)+lim的路径条数。

    求出最短路后,就可以dfs求解,为了处理环的情况传进两个参数x和lim。

    反向建图跑最短路可以优秀卡常,并且若跑完最短路后距离仍为INF就可以剪枝。

    然后是无解的情况,如果有0环则有无数解。方法是SPFA或者dfs记录状态,若从某状态再次搜到相同的状态则肯定有0环。SPFA可能被卡,所以采用Dijkstra+dfs判0环的方法。

    时间复杂度(O(K M))

    代码

    dfs

    中规中矩的记忆化搜索,是绝对的首选。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<queue>
    #include<cassert>
    #include<stack>
    #include<vector>
    template<class T>T read(T&x)
    {
    	T data=0;
    	int w=1;
    	char ch=getchar();
    	while(!isdigit(ch))
    	{
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    	{
    		data=data*10+ch-'0';
    		ch=getchar();
    	}
    	return x=data*w;
    }
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int INF=0x3f3f3f3f;
    
    const int MAXN=1e5+7,MAXM=2e5+7,MAXK=60;
    int n,m,k,mod;
    
    vector <pii> g1[MAXN],g2[MAXN];
    
    void init()
    {
    	read(n);read(m);read(k);read(mod);
    	for(int i=1;i<=n;++i)
    	{
    		g1[i].clear();
    		g2[i].clear();
    	}
    	for(int i=1;i<=m;++i)
    	{
    		int x,y,w;
    		read(x);read(y);read(w);
    		g1[x].push_back(pii(y,w));
    		g2[y].push_back(pii(x,w));
    	}
    }
    
    int dis[MAXN];
    
    void Dijkstra(int s)
    {
    	fill(dis+1,dis+n+1,INF);
    	dis[s]=0;
    	priority_queue <pii> H;
    	H.push(pii(-dis[s],s));
    	while(H.size())
    	{
    		int x=H.top().second,d=-H.top().first;
    		H.pop();
    		if(d>dis[x])
    			continue;
    		for(int i=0;i<g2[x].size();++i)
    		{
    			int y=g2[x][i].first,w=g2[x][i].second;
    			if(dis[y]>dis[x]+w)
    			{
    				dis[y]=dis[x]+w;
    				H.push(pii(-dis[y],y));
    			}
    		}
    	}
    }
    
    int add(int x,int y)
    {
    	x+=y;
    	return x>=mod?x-mod:x;
    }
    
    bool vis[MAXN][MAXK];
    bool ins[MAXN][MAXK];
    int f[MAXN][MAXK];
    
    int dfs(int x,int lim)
    {
    //	cerr<<"dfs "<<x<<" "<<lim<<endl;
    	if(vis[x][lim])
    		return f[x][lim];
    	if(ins[x][lim])
    		return -1;
    	ins[x][lim]=1;
    	int&ans=f[x][lim]=(x==n);
    	for(int i=0;i<g1[x].size();++i)
    	{
    		int y=g1[x][i].first,w=g1[x][i].second;
    		if(dis[y]==INF)
    			continue;
    		int delta=dis[y]+w-dis[x];
    		if(delta>lim)
    			continue;
    		int t=dfs(y,lim-delta);
    		if(t==-1)
    			return -1;
    		ans=add(ans,t);
    	}
    	vis[x][lim]=1;
    	ins[x][lim]=0;
    	return ans;
    }
    
    int main()
    {
    	freopen("park.in","r",stdin);
    	freopen("park.out","w",stdout);
    //	freopen("park.err","w",stderr);
    	int T;
    	read(T);
    	while(T--)
    	{
    		init();
    		Dijkstra(n);
    //		cerr<<"dis="<<endl;
    //		for(int i=1;i<=n;++i)
    //			cerr<<i<<" d="<<dis[i]<<endl;
    		for(int i=1;i<=n;++i)
    		{
    			fill(vis[i],vis[i]+k+1,0);
    			fill(ins[i],ins[i]+k+1,0);
    		}
    		printf("%d
    ",dfs(1,k));
    	}
    	return 0;
    }
    

    SPFA

    要是用SPFA就要有信仰了,不可能入队n次才判0环,不然肯定TLE。

    于是我逐渐去试,发现如果设成10会WA,设成11刚好能AC。出题人根本就没造网格图,但考试的时候谁又知道呢?

    然后就跑得飞快。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    template<class T>T read(T&x)
    {
    	T data=0;
    	int w=1;
    	char ch=getchar();
    	while(!isdigit(ch))
    	{
    		if(ch=='-')
    			w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    	{
    		data=data*10+ch-'0';
    		ch=getchar();
    	}
    	return x=data*w;
    }
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int INF=0x3f3f3f3f;
    
    const int MAXN=1e5+7,MAXM=2e5+7,MAXK=60;
    int n,m,k,mod;
    
    struct edge // g2
    {
    	int nx,to,w;
    }e[MAXM];
    int head[MAXN],ecnt;
    vector <pii> g[MAXN]; // g1
    
    void addedge(int x,int y,int w)
    {
    	e[++ecnt].to=y,e[ecnt].w=w;
    	e[ecnt].nx=head[x],head[x]=ecnt;
    }
    
    void init()
    {
    	read(n);read(m);read(k);read(mod);
    	ecnt=0;
    	fill(head+1,head+n+1,0);
    	for(int i=1;i<=n;++i)
    		g[i].clear();
    	for(int i=1;i<=m;++i)
    		{
    			int x,y,w;
    			read(x);read(y);read(w);
    			addedge(y,x,w);
    			g[x].push_back(pii(y,w));
    		}
    }
    
    bool inq[MAXN];
    int cnt[MAXN];
    int dis[MAXN];
    
    bool SPFA(int s)
    {
    	fill(inq+1,inq+n+1,0);
    	fill(cnt+1,cnt+n+1,0);
    	fill(dis+1,dis+n+1,INF);
    	dis[s]=0;
    	queue<int>Q;
    	Q.push(s);
    	inq[s]=1;
    	++cnt[s];
    	while(Q.size())
    	{
    		int x=Q.front();
    		Q.pop();
    		inq[x]=0;
    		for(int i=head[x];i;i=e[i].nx)
    		{
    			int y=e[i].to,w=e[i].w;
    			if(dis[y]>=dis[x]+w)
    			{
    				dis[y]=dis[x]+w;
    				if(!inq[y])
    				{
    					Q.push(y);
    					inq[y]=1;
    					if(++cnt[y]>=11) // 0 circle
    						return 0;
    				}
    			}
    		}
    	}
    	return 1;
    }
    
    int add(int x,int y)
    {
    	x+=y;
    	return x>=mod?x-mod:x;
    }
    
    bool vis[MAXN][MAXK];
    int f[MAXN][MAXK];
    
    int dfs(int x,int lim)
    {
    //	cerr<<"dfsing "<<x<<" lim="<<lim<<endl;
    	if(lim<0)
    		return 0;
    	if(vis[x][lim])
    		return f[x][lim];
    	int&ans=f[x][lim]=(x==n);
    	for(int i=0;i<g[x].size();++i)
    	{
    		int y=g[x][i].first,w=g[x][i].second;
    		if(!cnt[y]) // not accessible to n
    			continue;
    		int delta=dis[y]+w-dis[x];
    		ans=add(ans,dfs(y,lim-delta));
    	}
    	vis[x][lim]=1;
    //	cerr<<" ans="<<ans<<endl;
    	return ans;
    }
    
    int main()
    {
    	freopen("park.in","r",stdin);
    	freopen("park.out","w",stdout);
    //	freopen("park.err","w",stderr);
    	int T;
    	read(T);
    	while(T--)
    	{
    		init();
    		if(!SPFA(n)) // 0 circle
    		{
    			puts("-1");
    			continue;
    		}
    //		cerr<<"dis="<<endl;
    //		for(int i=1;i<=n;++i)
    //			cerr<<i<<" d="<<dis[i]<<endl;
    		for(int i=1;i<=n;++i)
    			fill(vis[i],vis[i]+k+1,0);
    		printf("%d
    ",dfs(1,k));
    	}
    	return 0;
    }
    

    Hint

    注意数组范围。

  • 相关阅读:
    public interface IBaseService<T> where T:class, new()含义
    mvc多条件查询
    jquery select下拉框和 easy-ui combox 选定指定项区别
    .net 中主框架的搭建(2种方式)
    linq ->sql & linq->lambda中的cud
    mvc中日志的原理和使用步骤
    Sprint.Net和Mvc结合使用
    2017.5.12总结
    c#前端验证和后台验证总结
    matlab根据url链接下载*.tar文件并解压
  • 原文地址:https://www.cnblogs.com/autoint/p/9931611.html
Copyright © 2011-2022 走看看