bzoj5056:OI游戏

题目描述:

小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的你来说,这不过是小菜一碟啦!

时间效率:$O(n^{2})$ 

以下代码:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=55,inf=1e9,p=1e9+7;
char s[N];bool vis[N];
int n,a[N][N],d[N],f[N],ans=1;
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        scanf(" %s",s+1);
        for(int j=1;j<=n;j++){
            if(s[j]=='0'&&i!=j)a[i][j]=inf;
            else a[i][j]=s[j]-'0';
        }
    }
    vis[1]=1;
    for(int i=1;i<=n;i++)d[i]=a[1][i],f[i]=1;d[0]=inf+1;
    for(int i=1;i<=n;i++){
        int x=0;
        for(int j=1;j<=n;j++){
            if(!vis[j]&&d[j]<d[x])x=j;
        }
        vis[x]=1;
        for(int j=1;j<=n;j++){
            if(x==j)continue;
            int w=d[x]+a[x][j];
            if(w<d[j])d[j]=w,f[j]=1;
            else if(w==d[j])f[j]++;
        }
    }
    for(int i=1;i<=n;i++)ans=1ll*f[i]*ans%p;
    printf("%d
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/10461422.html