【图论-矩阵快速幂】中山纪念中学暑期游Day9——迷路

前言

图论题一直是硬伤...

题目

windy在有向图中迷路了。
该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。
现在给出该有向图,你能告诉windy总共有多少种不同的路径吗?
注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

Input

第一行包含两个整数,N T。
接下来有 N 行,每行一个长度为 N 的字符串。
第i行第j列为'0'表示从节点i到节点j没有边。
为'1'到'9'表示从节点i到节点j需要耗费的时间。

Output

输出一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

Sample Input

2 2
11
00

Sample Output

1

【数据范围】

100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 

分析

正解:【矩阵快速幂】

具体见落谷:https://www.luogu.org/problemnew/solution/P4159

考试暴力12.5分代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=10,mod=2009;
char b[MAXN+5];
ll a[MAXN+5][MAXN+5];
ll n,t,ans;
void dfs(ll u,ll fa,ll dis)
{
	if(u==n&&dis==t)
	{
		ans++;
		ans%=mod;
		return ;
	}
	if(dis>t)
		return ;
	for(int i=1;i<=n;i++)
		if(a[u][i]&&i!=fa)
			dfs(i,u,dis+a[u][i]);
}
int main()
{
	scanf("%lld%lld",&n,&t);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",b+1);
		for(int j=1;j<=n;j++)
			a[i][j]=(ll)b[j]-'0'; 	
	} 
	dfs(1,0,0);
	printf("%lld",ans%mod);
	return 0;
}
//依然暴力...或许可以剪枝 

AC代码

自己打的矩阵加速,好有成就感

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=100,mod=2009;
int n,m,t;
struct Matrix
{
    int n,m;
    int a[MAXN+5][MAXN+5];
    Matrix(){memset(a,0,sizeof(a));}
    void clear()
    {
        memset(a,0,sizeof(a)); 
        for(int i=1;i<=n;i++)
            a[i][i]=1; 
    }
    Matrix operator*(const Matrix& b)
    {
        Matrix r;
        r.n=n;r.m=b.m;
        for(int i=1;i<=r.n;i++)
            for(int j=1;j<=r.m;j++)
                for(int k=1;k<=m;k++)
                {
                	r.a[i][j]+=a[i][k]*b.a[k][j];
                	r.a[i][j]%=mod;
				}
        return r;
    }
    Matrix operator^(int p)
	{
		Matrix r,x=*this;//x指当前这个结构体 
		r.n=n,r.m=m; 
		r.clear();
		for(;p;p>>=1,x=x*x)//快速幂 
			if(p&1)
				r=r*x;
		return r;
	} 
}f;
int pos(const int &u,const int &i)
{
	return u+i*n; 
}
int main()
{
    scanf("%d%d",&n,&t);
    f.m=f.n=n*9;
    int x;
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=8;j++)
    		f.a[pos(i,j)][pos(i,j-1)]=1;
    	for(int j=1;j<=n;j++)
    	{
    		scanf("%1d",&x);
    		f.a[i][pos(j,x-1)]=1;
		}
	}
	f=f^t;
	printf("%d",f.a[1][n]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值