nyoj-895How many ways【图上dp+拓扑序】
来源:互联网 发布:淘宝如何买报销假车票 编辑:程序博客网 时间:2024/04/29 18:40
How many ways?
- 描述
给一个 n 个点 m 条边的有向无环图,问从点 1 到点 n 一共有多少条路径?(结果对 10007 取模)
- 输入
- 多组测试数据。
第一行两个数,n 和 m(2<=n<=100,2<=m<=10000)。 - 输出
- 每组测试数据输出一行,表示从点 1 到点 n 的方案数对 10007 取模后的值。
首先,我分析这个问题是在图上的dp。
用dp[i][j]表示 从i点->j点的最大路径数
dp[0][j]记录到j点总的最大路径数
g[i][j]表示i点到j点的的边数
状态转移方程为:
dp[u][v]=Max(dp[0][u]*g[u][v]);
dp[0][v]=∑(Max(dp[u][v]));u为所有能连接到v的点
总体意思就是一个点的最大路径数为 sum v= ∑( sum u * count_e ); v的最大路径数 = 所有的 (v的最大路径数 * v到u的边数)之和
接下来就是枚举所有边,更新dp值。一个点的dp值被改变了,那么它连接的点及其以后的dp值都是可变的。所以不断的枚举所有边更新dp值,直到再没有点更新为止。
#include <stdio.h>#include <stdlib.h>#include <string.h>#define Max_V 110long long int dp[Max_V][Max_V];long long int g[Max_V][Max_V];int n,m;void init(){memset(dp,0,sizeof(dp));memset(g,0,sizeof(g));}int main(){int i;while(~scanf("%d%d",&n,&m)){init();int u,v;for(i=0;i<m;i++){scanf("%d%d",&u,&v);g[u][v]++;}dp[0][1]=1;//从1点出发bool flag=true;while(flag){flag=false;//枚举所有边for(u=1;u<=n;u++)for(v=1;v<=n;v++){if(dp[u][v]<g[u][v]*dp[0][u]){flag=true;//dp[0][v]记录最大路径数,//更新前的dp[u][v]无效后就得减去//再加上更新后的dp[u][v]dp[0][v]-=dp[u][v];dp[u][v]=g[u][v]*dp[0][u];dp[0][v]+=dp[u][v];}}}printf("%lld\n",dp[0][n]%10007);}return 0;}
但是,问题就来了。数据范围十分的大,远超过long long int。因为求模之后比较大小是无效的。那么怎么解决这个问题呢?
关键字:有向无环图
联想:DAG(拓扑排序)
由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。
重复执行
(1) 选择一个入度为0的顶点;
(2) 从网中删除此顶点及所有出边。
这样就不断列举出入度为0的点。
承接上面的思路。一个点的入度为0,是不是就说明这个点就不会再被其它点更新了?是不是就说明这个点已经更新到底了?
那么 dp[0][u]就不会再改变了。dp[u][v]也随之固定。这样问题就变成了一个单纯的递推式,并且dp[]数组可以从二维优化到一维:dp[v]+=dp[u]*g[u][v];因为dp[u]固定(u入度为0,所以dp[u]不会再被更改,所以dp[u]当前为最大路径数),g[u][v]固定。
就不需要再判断大小了。就可以利用取模运算了。
所以在此点更新了其它点之后,此点及其出边就可以删除了,这样又会创造出入度为0的点。
#include <stdio.h>#include <string.h>#include <stdlib.h>#define Max_V 110#define mod 10007int n,m;int indeg[Max_V];int g[Max_V][Max_V];int dp[Max_V];bool vis[Max_V];void init(){memset(indeg,0,sizeof(indeg));memset(g,0,sizeof(g));memset(dp,0,sizeof(dp));memset(vis,0,sizeof(vis));}int main(){int i;while(~scanf("%d%d",&n,&m)){init();int u,v;for(i=0;i<m;i++){scanf("%d%d",&u,&v);g[u][v]++;indeg[v]++;}dp[1]=1;while(true){for(u=1;u<=n;u++)//寻找未删除的0度顶点if(!indeg[u]&&!vis[u])break;if(u>=n)break;vis[u]=1;//标记数组表示删除该点for(v=1;v<=n;v++)if(g[u][v]){dp[v]+=dp[u]*g[u][v];//(a+b)%m=(a%m+b%m)%mdp[v]%=mod;indeg[v]-=g[u][v];//减少入度表示删除此点的出边}}printf("%d\n",dp[n]);}return 0;}
- nyoj-895How many ways【图上dp+拓扑序】
- How many ways-dp
- nyoj How many ways?? 2157 (DP) 好题
- HDU1978 How many ways 【DP】
- HDU 1978 How many ways (DP)
- hdu 1978 How many ways(dp)
- 【HDU1978】How many ways DP行走方式
- HDU 1978 How many ways(DP)
- How many ways - HDU 1978 dp
- HDU 1978 How many ways(DP)
- HDU 1978 How many ways (DP,计数)
- poj - 1978 - How many ways(dp)
- 【DP|水】HDU-1978 How many ways
- HDU 1978 How many ways(DP)
- HDU 2157 How many ways?? (DP)
- HDU 1978 How many ways (DP)
- HDOJ 2157 How many ways?? (DP)
- hdu1978 How many ways(DP)
- forward 和 redirect 的区别?
- Generate Parentheses
- java 开发环境的安装
- message queue & event loop
- 我要hg0088开户程序哪里找
- nyoj-895How many ways【图上dp+拓扑序】
- IOS之OC入门--封装
- XML、JSON数据结构解析
- SQLServer复制需要有实际的服务器名称才能连接到服务器,请指定实际的服务器名
- vs release版本
- Ubuntu14.04 kylin 忘记root密码的解决方法
- [Python]网络爬虫(三):异常的处理和HTTP状态码的分类
- hadoop HDFS结构
- spring中classpath与classpath*