Hdu 2157 How many ways??(DP||矩陣乘法)

How many ways??
Time Limit:1000 MS Memory Limit: 32768 K
Problem Description
春天到了, HDU校園裏開滿了花, 奼紫嫣紅, 非常美麗. 蔥頭是個愛花的人, 看着校花校草競相開放, 漫步校園, 心情也變得舒暢. 爲了多看看這迷人的校園, 蔥頭決定, 每次上課都走不同的路線去教室, 但是由於時間問題, 每次只能經過k個地方, 比方說, 這次蔥頭決定經過2個地方, 那他可以先去問鼎廣場看看噴泉, 再去教室, 也可以先到體育場跑幾圈, 再到教室. 他非常想知道, 從A 點恰好經過k個點到達B點的方案數, 當然這個數有可能非常大, 所以你只要輸出它模上1000的餘數就可以了. 你能幫幫他麼?? 你可決定了蔥頭一天能看多少校花哦
Input
輸入數據有多組, 每組的第一行是2個整數 n, m(0 < n <= 20, m <= 100) 表示校園內共有n個點, 爲了方便起見, 點從0到n-1編號,接着有m行, 每行有兩個整數 s, t (0<=s,t< n) 表示從s點能到t點, 注意圖是有向的.接着的一行是兩個整數T,表示有T組詢問(1<=T<=100),
接下來的T行, 每行有三個整數 A, B, k, 表示問你從A 點到 B點恰好經過k個點的方案數 (k < 20), 可以走重複邊。如果不存在這樣的走法, 則輸出0
當n, m都爲0的時候輸入結束
Output
計算每次詢問的方案數, 由於走法很多, 輸出其對1000取模的結果
Sample Input
4 4
0 1
0 2
1 3
2 3
2
0 3 2
0 3 3
3 6
0 1
1 0
0 2
2 0
1 2
2 1
2
1 2 1
0 1 3
0 0
Sample Output
2
0
1
3
Author
小黑
Source
2008信息工程學院集訓隊——選拔賽

/*
DP做法.
dp[i][j]表示到i點走了j步的方案數.
dp[i][j]=∑dp[k][j-1](a[k][i]=true).
複雜度O(N^2KT).
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 101
#define mod 1000
using namespace std;
int a[MAXN][MAXN],n,m,t,dp[MAXN][MAXN];
int main()
{
    int x,y,K;
    while(~scanf("%d%d",&n,&m))
    {
        if(!n&&!m) break;
        memset(a,0,sizeof a);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            x++,y++;
            a[x][y]=1;
        }
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&x,&y,&K);
            memset(dp,0,sizeof dp);
            x++,y++;
            dp[x][0]=1;
            for(int k=1;k<=K;k++)
              for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    if(i==j) continue;
                    dp[i][k]=(dp[i][k]+dp[j][k-1]*a[j][i])%mod;
                }
            printf("%d\n",dp[y][K]);
        }
    }
    return 0;
}
/*
矩陣乘法,圖論.
對鄰接矩陣作k次冪相乘.
自乘K次後ans[i][j]表示
從i到j經過K-1個點(路徑長度爲K)的方案數.
複雜度O(N^3Log2kT)
but 蜜汁T 複雜度完全可以啊啊啊啊啊.
*/
#include<cstdio>
#define MAXN 101
#define mod 1000
using namespace std;
int n,m,ans[MAXN][MAXN],b[MAXN][MAXN],c[MAXN][MAXN],s[MAXN][MAXN];
void mi(int k)
{
    while(k)
    {
        if(k&1)
        {
            for(int i=1;i<=n;i++)
              for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                  c[i][j]=(c[i][j]+ans[i][k]*b[k][j])%mod;
            for(int i=1;i<=n;i++)
              for(int j=1;j<=n;j++)
                ans[i][j]=c[i][j],c[i][j]=0;
        }
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
              c[i][j]=(c[i][j]+b[i][k]*b[k][j])%mod;
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            b[i][j]=c[i][j],c[i][j]=0;
        k>>=1;
    }
}
int main()
{
    int x,y,t,K;
    while(true)
    {
        scanf("%d%d",&n,&m);
        if(!n&&!m) break;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            x++,y++;
            s[x][y]=ans[x][y]=b[x][y]=1;
        }
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&x,&y,&K);
            x++,y++;
            for(int i=1;i<=n;i++)
              for(int j=1;j<=n;j++)
                ans[i][j]=b[i][j]=s[i][j];
            K--;
            mi(K);
            printf("%d\n",ans[x][y]);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章