P3953 逛公园
2024-08-30 02:40:33
传送门
花了一个下午才 A 的毒瘤题
思路:
这题需要建两个图,一个正向图,一个反向图。
先在正向图上跑一遍 dijkstar ,计算出每个点到 点1 的最短路径 。
然后在反向图上开始记忆化搜索:
- 和动规一样,先定义 f [ i ][ j ] 表示:从 点 1 到 点 i 的距离为 dis [ i ] + j 的方案数。(初始值要为负,不然判断 0环 的时候会出错)
- 对于每一条反向边(u,v,w)都有 f [ u ][ d ] = ∑ f [ u ][(dis[ u ] + d)-(dis[ v ] + w)] 。
设 lck_dis = (dis[ u ] + d)-(dis[ v ] + w)。
仔细分析会发现 lck_dis 就表示 点 u 到 起点 1 的距离。
这类似于 最短路计数 的转移,因为建的是反向边,所以要从后往前转移。
- 为了判断是否有毒瘤的 0边,需要开一个布尔数组 flag [ i ][ j ] 判断 dp 值是否被经过 2 次,且没有被确定,那么一定是有 0边 导致的自环。
Code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<string>
#include<stack>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<set>
using namespace std;
#define INF 0x3f
const int maxn=1e5+;
inline int read()
{
int xs=,kr=;
char ls;
ls=getchar();
while(!isdigit(ls))
{
if(ls=='-')
kr=-;
ls=getchar();
}
while(isdigit(ls))
{
xs=(xs<<)+(xs<<)+(ls^);
ls=getchar();
}
return xs*kr;
}
int T,n,m,k,p;
long long ans;
int head_dij[maxn],head_dfs[maxn],dis[maxn],f[maxn][];
bool bo,vis[maxn],flag[maxn][];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct hh
{
int nex,to,w;
} t_dij[maxn<<],t_dfs[maxn<<];
inline void clear()
{
bo=false;
memset(head_dij,,sizeof(head_dij));
memset(head_dfs,,sizeof(head_dfs));
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(f,-,sizeof(f));
}
inline void add(int cnt,int nex,int to,int w)
{
t_dij[cnt].to=to; t_dij[cnt].w=w;
t_dij[cnt].nex=head_dij[nex]; head_dij[nex]=cnt; t_dfs[cnt].to=nex; t_dfs[cnt].w=w;
t_dfs[cnt].nex=head_dfs[to]; head_dfs[to]=cnt;
}
inline void dijkstra(int s)
{
dis[s]=;
q.push(make_pair(,s));
while (!q.empty())
{
int u=q.top().second;
q.pop();
if (vis[u]) continue;
vis[u]=true;
for (int i=head_dij[u];i;i=t_dij[i].nex)
{
int v=t_dij[i].to,w=t_dij[i].w;
if (!vis[v]&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push(make_pair(dis[v],v));
}
}
}
}
int dfs(int u,int d)
{
if (flag[u][d])
{
bo=true;
return ;
}
if (~f[u][d]) return f[u][d];
flag[u][d]=true;f[u][d]=;
for (int i=head_dfs[u];i;i=t_dfs[i].nex)
{
if(bo) break;
int v=t_dfs[i].to,w=t_dfs[i].w;
int lck_dis=(dis[u]+d)-(w+dis[v]);
if (lck_dis>=) f[u][d]=(f[u][d]+dfs(v,lck_dis))%p;
}
flag[u][d]=false;
if (u==&&!d) return ++f[u][d];
return f[u][d];
}
int x,y,z;
int main()
{
//freopen("park.in","r",stdin);
//freopen("park.out","w",stdout);
T=read();
while (T--)
{
clear();
n=read();m=read();k=read();p=read();
for(int i=;i<=m;i++)
{
x=read();y=read();z=read();
add(i,x,y,z);
}
dijkstra();
ans=dfs(n,)%p;
for(int i=;i<=k;i++)
{
if(bo) break;
ans=(ans+dfs(n,i))%p;
}
if(bo) printf("-1\n");
else printf("%lld\n",ans);
}
return ;
}
注:在 dfs 中,if ( ~ f [ u ][ d ] ) ⇔ if ( f [ u ][ d ] ≥ 0 ) 。有助于卡常
最新文章
- Memcache学习整理
- 如丝般顺滑地从Windows迁移SQLServer数据库到Linux
- 从语言到库到框架,再到API,再到标记最后到DSL语言
- Cannot return from outside a function or method
- gitlab 用户头像不能显示的问题
- Longest Palindromic Substring
- Linux的启动过程
- mybatis中oracle in>;1000的处理
- CentOS如何挂载硬盘
- 【转】android出现注: 某些输入文件使用或覆盖了已过时的 API。 注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。 注: 某些输入文件使用了未经检查或不安全的操作。 注
- 【译】 AWK教程指南 8处理多行数据
- ajax调用webService中的方法
- java MessageFormat 应用 和 疑惑
- MD5和SHA512Managed ——哈希算法
- UVA 674 (入门DP, 14.07.09)
- dede 你所上传的软件类型不在许可列表,请更改系统对扩展名限定的配置
- 第十三课 CSS外观及样式的应用 css学习3
- jQuery的deferred对象解析
- How to proof MD5
- January 05th, 2018 Week 01st Friday
热门文章
- mac上sed -i 执行失败报错
- CF830A Office Keys(贪心)
- 阿里云mysql安装配置(CentOS 7.3 64)
- 北京大学Cousera学习笔记--3-计算导论与C语言基础-第一讲.计算机的基本原理-计算机怎么计算-数的二进制
- servlet中如何实现通过Spring实现对象的注入
- 统计Oracle一个表空间中各个segment占用的空间大小
- jquery.uploadify上传插件HTML5版中文api使用说明
- Oracle树查询及相关函数
- 通过浏览器F12开发工具快速获取别的网站前端代码的方法
- jquery的cookie插件