目录
P4316
题意:
给
一
个
D
A
G
,
从
1
出
发
,
每
次
等
概
率
地
走
这
个
点
能
走
的
边
,
给一个DAG,从1出发,每次等概率地走这个点能走的边,
给一个DAG,从1出发,每次等概率地走这个点能走的边,
问
走
到
n
点
的
期
望
路
径
长
度
为
多
少
?
问走到n点的期望路径长度为多少?
问走到n点的期望路径长度为多少?
思路:
首
先
这
是
一
道
典
型
的
概
率
D
P
,
用
d
p
[
i
]
表
示
现
在
在
i
点
到
达
n
点
首先这是一道典型的概率DP,用dp[i]表示现在在i点到达n点
首先这是一道典型的概率DP,用dp[i]表示现在在i点到达n点
还
需
要
走
的
路
径
长
度
的
期
望
,
那
么
d
p
[
n
]
=
0
,
而
d
p
[
1
]
就
是
答
案
还需要走的路径长度的期望,那么dp[n] = 0,而dp[1]就是答案
还需要走的路径长度的期望,那么dp[n]=0,而dp[1]就是答案
对
于
一
条
边
对于一条边
对于一条边
u
−
>
v
u->v
u−>v
d p [ u ] = ∑ ( d p [ v ] + w ) d e g [ u ] dp[u] = ∑\frac{(dp[v] + w)}{deg[u]} dp[u]=∑deg[u](dp[v]+w)
因
为
d
p
[
n
]
=
0
因为dp[n] = 0
因为dp[n]=0,
且
是
个
D
A
G
即
后
面
的
值
一
旦
确
定
,
不
会
改
变
且是个DAG即后面的值一旦确定,不会改变
且是个DAG即后面的值一旦确定,不会改变,
从
后
面
往
前
推
,
建
反
图
从后面往前推,建反图
从后面往前推,建反图
#include <cstdio>
#include <iostream>
#include <cmath>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e5+10;
int head[N],idx,deg[N],order[N],k;
struct Node{
int to,nex;
double w;
}e[N<<1];
double dp[N];
void add_edge(int u,int v,double w){
e[idx].to = v;
e[idx].w = w;
e[idx].nex = head[u];
head[u] = idx++;
}
int n,m;
void topo(){
int in[N],k = 0;
queue<int> q;
memset(in,0,sizeof(in));
for(int i = 1;i <= n;i++){
in[i] = deg[i];
if(!in[i]) q.push(i);
}
while(q.size()){
int u = q.front();q.pop();
order[k++] = u;
for(int i = head[u];~i;i = e[i].nex){
int v = e[i].to;
dp[v] += (dp[u] + e[i].w) / deg[v];
if(--in[v] == 0) q.push(v);
}
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
int u,v;scanf("%d%d",&u,&v);
double w;scanf("%lf",&w);
add_edge(v,u,w);deg[u]++;
}
topo();
printf("%.2lf\n",dp[1]);
return 0;
}
P1351
题意:
給
一
颗
树
,
边
权
均
为
1
,
求
出
两
点
距
离
为
2
的
两
点
乘
积
之
和
,
給一颗树,边权均为1,求出两点距离为2的两点乘积之和,
給一颗树,边权均为1,求出两点距离为2的两点乘积之和,
还
有
乘
积
的
最
大
值
还有乘积的最大值
还有乘积的最大值
思路:
枚
举
中
间
点
是
哪
个
点
枚举中间点是哪个点
枚举中间点是哪个点
遍
历
以
这
个
点
为
中
间
的
点
对
:
遍历以这个点为中间的点对:
遍历以这个点为中间的点对:
当
有
两
个
邻
点
时
,
对
答
案
贡
献
为
2
a
b
=
(
a
+
b
)
2
−
(
a
2
+
b
2
)
当有两个邻点时,对答案贡献为2ab = (a+b)^2 - (a^2+b^2)
当有两个邻点时,对答案贡献为2ab=(a+b)2−(a2+b2)
三
个
邻
点
时
,
对
答
案
贡
献
为
2
a
b
+
2
a
c
+
2
b
c
=
(
a
+
b
+
c
)
2
−
(
a
2
+
b
2
+
c
2
)
三个邻点时,对答案贡献为2ab+2ac+2bc = (a+b+c)^2 - (a^2+b^2+c^2)
三个邻点时,对答案贡献为2ab+2ac+2bc=(a+b+c)2−(a2+b2+c2)
均
能
写
成
权
值
和
的
平
方
减
去
平
方
的
和
均能写成权值和的平方减去平方的和
均能写成权值和的平方减去平方的和
最
大
值
就
看
下
邻
点
权
值
的
最
大
值
和
次
大
值
相
乘
能
不
能
更
新
答
案
最大值就看下邻点权值的最大值和次大值相乘能不能更新答案
最大值就看下邻点权值的最大值和次大值相乘能不能更新答案
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
const int mod = 1e4+7;
struct Node{
int to,nex;
}e[N<<1];
int head[N],idx;
void add_edge(int u,int v){
e[idx].to = v;
e[idx].nex = head[u];
head[u] = idx++;
}
int n,val[N];
int mx,ans;
void solve(){
//枚举中间点
for(int u = 1;u <= n;u++){
int d1 = 0,d2 = 0;//最大值,次大值
int tmp1 = 0,tmp2 = 0;
for(int i = head[u];~i;i = e[i].nex){
int v = e[i].to;
if(val[v] > d1) d2 = d1,d1 = val[v];
else if(val[v] > d2) d2 = val[v];
tmp1 = (tmp1 + val[v]) % mod;
tmp2 = (tmp2 + val[v]*val[v]%mod) % mod;
}
tmp1 = tmp1 * tmp1 % mod;
ans = (ans + tmp1 - tmp2 + mod) % mod;
if(d1*d2 > mx) mx = d1*d2;
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i = 1,u,v;i < n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v),add_edge(v,u);
}
for(int i = 1;i<= n;i++) scanf("%d",val+i);
solve();
printf("%d %d\n",mx,ans);
return 0;
}
P1144
题意:
给 一 个 无 向 无 权 图 , 计 算 出 从 1 出 发 到 各 点 的 最 短 路 条 数 给一个无向无权图,计算出从1出发到各点的最短路条数 给一个无向无权图,计算出从1出发到各点的最短路条数
思路:
这
题
无
权
值
,
可
以
用
b
f
s
解
决
,
有
一
题
更
一
般
的
题
目
U
E
S
T
C
−
1147
这题无权值,可以用bfs解决,有一题更一般的题目UESTC-1147
这题无权值,可以用bfs解决,有一题更一般的题目UESTC−1147
传送门
这
题
还
要
处
理
答
案
是
不
是
无
穷
无
尽
的
问
题
这题还要处理答案是不是无穷无尽的问题
这题还要处理答案是不是无穷无尽的问题
首
先
思
考
为
什
么
会
出
现
无
穷
无
尽
的
答
案
,
因
为
边
权
允
许
为
0
首先思考为什么会出现无穷无尽的答案,因为边权允许为0
首先思考为什么会出现无穷无尽的答案,因为边权允许为0
设
想
只
要
有
一
个
在
1
到
n
最
短
路
上
的
点
,
他
有
一
条
边
权
为
0
的
出
边
设想只要有一个在1到n最短路上的点,他有一条边权为0的出边
设想只要有一个在1到n最短路上的点,他有一条边权为0的出边
那
么
只
要
在
经
过
这
个
点
的
时
候
走
一
次
这
条
边
权
为
0
的
边
是
一
个
方
案
那么只要在经过这个点的时候走一次这条边权为0的边是一个方案
那么只要在经过这个点的时候走一次这条边权为0的边是一个方案
走
两
次
,
走
三
次
.
.
.
.
.
都
是
一
个
方
案
走两次,走三次.....都是一个方案
走两次,走三次.....都是一个方案
因
此
出
现
了
无
穷
无
尽
因此出现了无穷无尽
因此出现了无穷无尽
因
此
只
要
在
更
新
过
程
中
,
不
允
许
出
现
这
种
情
况
,
因此只要在更新过程中,不允许出现这种情况,
因此只要在更新过程中,不允许出现这种情况,
一
出
现
就
把
路
径
数
量
设
为
−
1
一出现就把路径数量设为-1
一出现就把路径数量设为−1
P 1144 C o d e P1144Code P1144Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e6+10;
const int mod = 1e5+3;
struct Edge{
int to,nex,w;
}e[N<<1];
int head[N],idx;
int dist[N],ans[N];
bool st[N];
void add_edge(int u,int v,int w){
e[idx].to = v;
e[idx].w = w;
e[idx].nex = head[u];
head[u] = idx++;
}
int n,m;
priority_queue < pair<int,int> > q;
void Dij(int s){
dist[s] = 0;
ans[s] = 1;
q.push(make_pair(0,s));
while(q.size()){
int u = q.top().second;q.pop();
if(st[u]) continue;
st[u] = 1;
for(int i = head[u];~i;i = e[i].nex){
int v = e[i].to;
if(dist[v] > dist[u] + e[i].w){
dist[v] = dist[u] + e[i].w;
ans[v] = ans[u];
q.push(make_pair(-dist[v],v));
}else if(dist[v] == dist[u] + e[i].w){
ans[v] = (ans[v] + ans[u]) % mod;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(dist,inf,sizeof(dist));
for(int i = 0,u,v;i < m;i++){
scanf("%d%d",&u,&v);
add_edge(u,v,1),add_edge(v,u,1);
}
Dij(1);
for(int i = 1;i <= n;i++){
printf("%d\n",ans[i]);
}
return 0;
}
U E S T C − 1147 C o d e UESTC-1147Code UESTC−1147Code
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2e3+10;
const int inf = 0x3f3f3f3f;
const int mod = 1000000009;
int head[N],idx;
int dist[N],ans[N];
bool st[N];
struct Edge{
int to,nex,w;
}e[N<<1];
void add_edge(int u,int v,int w){
e[idx].to = v;
e[idx].nex = head[u];
e[idx].w = w;
head[u] = idx++;
}
void Dij(int s){
dist[s] = 0,ans[s] = 1;
priority_queue< pair<int,int> > q;
q.push(make_pair(0,s));
while(q.size()){
int u = q.top().second;q.pop();
if(st[u]) continue;
st[u] = 1;
for(int i = head[u];~i;i = e[i].nex){
int v = e[i].to,w = e[i].w;
if(dist[v] > dist[u] + w){
dist[v] = dist[u] + w;
if(w == 0) ans[v] = -1;
else ans[v] = ans[u];
q.push(make_pair(-dist[v],v));
}else if(dist[v] == dist[u] + w){
if(w == 0){
ans[v] = -1;
}else if(ans[u] == -1 || ans[v] == -1){
ans[v] = -1;
}else ans[v] = (ans[u] + ans[v]) % mod;
}
}
}
}
int n,m;
int main(){
memset(head,-1,sizeof(head));
memset(dist,inf,sizeof(dist));
scanf("%d%d",&n,&m);
for(int i = 0,u,v,w;i < m;i++){
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w),add_edge(v,u,w);
}
Dij(1);
printf("%d\n",ans[n]);
return 0;
}