华师一附中OI组
标题:
NOIP2017 逛公园 洛谷3953(Day1 T3)
[打印本页]
作者:
WWX
时间:
2018-6-5 20:06
标题:
NOIP2017 逛公园 洛谷3953(Day1 T3)
本帖最后由 WWX 于 2018-6-5 20:07 编辑
https://www.luogu.org/problemnew/show/P3953
题目很长,就不贴了
此题值得仔细思考,品味。
在写这题之前,建议先完成
路径统计
洛谷1068(
https://www.luogu.org/problemnew/show/P1608
)以及
最短路计数
洛谷1144(
https://www.luogu.org/problemnew/show/P1144
)
我们发现k的范围只有50,所以可以考虑用dp来解决这个问题
我们用dp[j]表示到节点i的长度为dis+j的路径条数dis为到节点i的最短距离
然后就可以写出转移方程dp
[j]+=dp[k][j-(dis[j]-dis[k]+dis
[j])]k为所用可以到达i的节点
在考虑什么时候会有无数条路径,显然是当图存在0环的时候
我们打一个标记在统计时判断一下,就好了
由于不太好推,我们利用记忆化搜索来实现代码
作者:
WWX
时间:
2018-6-5 20:08
# include<algorithm>
# include<iostream>
# include<cstring>
# include<cstdio>
# include<queue>
const int mn = 100010;
const int maxn = 200010;
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
using namespace std;
int t,n,m,K,p,ans,edge_max;
int dp[mn][51],mark[mn][51];
int dis[mn],head1[mn],head2[mn];
bool flag;
bool vis[mn];
queue<int> q;
struct edge{int to,dis,next;}e1[maxn],e2[maxn];
void add(int x,int y,int z)
{
e1[++edge_max].to=y;
e1[edge_max].dis=z;
e1[edge_max].next=head1[x];
head1[x]=edge_max;
e2[edge_max].to=x;
e2[edge_max].dis=z;
e2[edge_max].next=head2[y];
head2[y]=edge_max;
}
void pre()
{
dis[1]=0;
q.push(1);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head1[u];i;i=e1[i].next)
{
if(dis[u]+e1[i].dis<dis[e1[i].to])
{
dis[e1[i].to]=dis[u]+e1[i].dis;
if(!vis[e1[i].to])
{
vis[e1[i].to]=1;
q.push(e1[i].to);
}
}
}
}
}
int dfs(int x,int k)
{
if(flag)
return 0;
if(mark[x][k]==1)//如果有0环,路径则有无数条
{
flag=true;
return 0;
}
if(mark[x][k]==2)
return dp[x][k];
mark[x][k]=1;
for(int i=head2[x];i;i=e2[i].next)
{
int u=e2[i].to,len=e2[i].dis;
if(dis[u]+len>dis[x]+k)
continue;
dp[x][k]+=dfs(u,k-(dis[u]+len-dis[x]));
if(flag) return 0;
dp[x][k]%=p;
}
mark[x][k]=2;
return dp[x][k];
}
int main()
{
int x,y,z;
t=read();
while(t--)
{
ans=0;
flag=false;
memset(dis,0xf,sizeof(dis));
memset(head1,0,sizeof(head1));
memset(head2,0,sizeof(head2));
memset(dp,0,sizeof(dp));
memset(mark,0,sizeof(mark));
edge_max=0;
n=read(),m=read(),K=read(),p=read();
for(int i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
add(x,y,z);
}
pre();
dp[1][0]=1;
for(int i=0;i<=K;i++)
{
ans+=dfs(n,i);
//printf("%d\n",ans);
ans%=p;
}
if(flag)
puts("-1");
else printf("%d\n",ans);
}
return 0;
}
复制代码
作者:
胡雨菲菲
时间:
2018-6-7 14:42
太强了!%%%
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2