【bzoj5056】OI游戏

来源:互联网 发布:java 单例模式优点 编辑:程序博客网 时间:2024/05/17 23:25

Description

小Van的CP最喜欢玩与OI有关的游戏啦~小Van为了讨好她,于是冥思苦想,终于创造了一个新游戏。
下面是小Van的OI游戏规则:
给定一个无向连通图,有N个节点,编号为0~N-1。图里的每一条边都有一个正整数权值,边权在1~9之间。
要求从图里删掉某些边(有可能0条),使得剩下的图满足以下两个条件:
1) 剩下的图是一棵树,有N-1条边。
2) 对于所有v (0 < v < N),0到v的最短路(也就是树中唯一路径长度)和原图中的最短路长度相同。
最终要报出有多少种不同的删法可以满足上述条件。(两种删法不同当且仅当存在两个点,
一种删法删完之后这两个点之间存在边而另外一种删法不存在。)
由于答案有可能非常大,良心的小Van只需要答案膜1,000,000,007的结果。
后记: 然而这游戏太高难度了,小Van的CP做不出来因此很不开心!
她认为小Van在故意刁难她,于是她与小Van分手了。。。
不过对于精通OI的你来说,这不过是小菜一碟啦!
Input

第一行一个整数N,代表原图结点。
接下来N行,每行N个字符,描绘了一个邻接矩阵。邻接矩阵中,
如果某一个元素为0,代表这两个点之间不存在边,
并且保证第i行第i列的元素为0,第i行第j列的元素(i≠j)等于第j行第i列的元素。
2≤N≤50
Output

一行一个整数,代表删法总方案数膜1,000,000,007的结果。
Sample Input

Input1

2

01

10

Input2

4

0123

1012

2101

3210
Sample Output

Output1

1

Output2

6

题解
以0为根的最短路径图数目。
先跑最短路,然后判断每个点能成为哪些点的根,乘法原理相乘即可。

代码

#include<bits/stdc++.h>#define pa pair<ll,ll>typedef long long ll;const int mod=1000000007;const int N=500005;using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int f[55][55],dis[55],sum[55],n;bool vis[55];char s[55];void spfa(){    for (int i=2;i<=n;i++) dis[i]=mod;    queue<int>q;q.push(1);vis[1]=1;    while (!q.empty())    {        int now=q.front();q.pop();        for (int i=2;i<=n;i++)        {            if (!f[now][i]) continue;            if (dis[i]>dis[now]+f[now][i])            {                dis[i]=dis[now]+f[now][i];                if (!vis[i]) q.push(i),vis[i]=1;            }        }        vis[now]=0;    }}int main(){    n=read();    for (int i=1;i<=n;i++)    {        scanf("%s",s+1);        for (int j=1;j<=n;j++)            f[i][j]=s[j]-'0';    }    spfa();    for (int i=1;i<=n;i++)        for (int j=2;j<=n;j++)            if (dis[i]+f[i][j]==dis[j]&&i!=j&&f[i][j]!=0) sum[j]++;    ll ans=1;    for (int i=2;i<=n;i++) ans=ans*sum[i]%mod;    cout<<ans;    return 0;}