【bzoj5056】OI游戏

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值