题目描述:
小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; }