[BZOJ1875][SDOI2009]HH去散步(矩阵快速幂)
2016-05-23 20:49
253 查看
题目描述
传送门题解
对于读进来的两个点x,y,x->y,y->x;对于三个点x,y,z,如果存在边i使x->y,边j使y->z,那么在邻接矩阵G里将(i,j)赋为1.
求Gt−1即可.
解释一下,这里将一条双向边拆成两条单向边,并且只有连续的连边关系才能在邻接矩阵里标记,目的是不能走回头路.
构造好邻接矩阵之后,相当于构造出了一个新的图,这个图里的点相当于是原图里的一条边,那么在原图里恰好要经过t条边,在新的图里就要经过t个点,即t-1条边.并且这样的建图方式保证在新图里也不会走回头路,因为两条边不可能互相连边。
感觉这个思路很厉害呀。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int max_n=25; const int max_m=65; const int max_N=max_m*2; const int max_M=max_N*max_N; const int max_e=max_M*2; const int Mod=45989; int n,m,t,st,end,x,y,final; int tot,point[max_N],nxt[max_e],v[max_e]; struct hp{int a[max_N][max_N];}G,unit,ans; inline void addedge(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; } inline hp cheng(hp a,hp b) { hp ans; memset(ans.a,0,sizeof(ans.a)); for (int i=0;i<=tot;++i) for (int j=0;j<=tot;++j) for (int k=0;k<=tot;++k) ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%Mod)%Mod; return ans; } inline hp matrix_fast_pow(hp a,int p) { hp ans=unit; for (;p;p>>=1,a=cheng(a,a)) if (p&1) ans=cheng(ans,a); return ans; } int main() { scanf("%d%d%d%d%d",&n,&m,&t,&st,&end); st++; end++; tot=-1; memset(point,-1,sizeof(point)); memset(nxt,-1,sizeof(nxt)); for (int i=1;i<=m;++i) { scanf("%d%d",&x,&y); x++; y++; addedge(x,y); } for (int i=0;i<=tot;++i) unit.a[i][i]=1; for (int i=0;i<=tot;++i) for (int j=point[v[i]];j!=-1;j=nxt[j]) if (i!=(j^1)) G.a[i][j]++; ans=matrix_fast_pow(G,t-1); for (int i=point[st];i!=-1;i=nxt[i]) for (int j=point[end];j!=-1;j=nxt[j]) final=(final+ans.a[i][j^1])%Mod; printf("%d\n",final); }
总结
首先这道题新学到的思想:化边为点,双向边拆两条单向边。相关文章推荐
- HDOJ1010 STILL DFS
- NYOJ - 27 水池数目
- 导航抽屉图标+文字
- 导航抽屉图标+文字
- 设计模式 - Proxy模式
- hdoj2040亲和数
- LK源码解析 9 总结
- 初次接受C语言游戏程序感受
- [JZOJ3397]雨天的尾巴
- 2016百度之星 hdu 5695 拓扑序+优先队列
- linux ntp安装简单配置
- intent-filter data Uri 意图过滤器 详解
- LK源码解析 8 exceptions.S
- LK源码解析 7 aboot.c
- poj3264题解
- python的类
- 虚函数
- iptables 实现端口映射的实际用途
- LK源码解析 6 aboot.c
- 如何解析带JS动态的网页?