5056: OI游戏
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 204 Solved: 162
[Submit][Status][Discuss]
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
2
01
10
Input2
4
0123
1012
2101
3210
Sample Output
Output1
1
Output2
6
1
Output2
6
HINT
Source
赤裸裸的矩阵树定理。
有向图的外向生成树个数=(入度矩阵-邻接矩阵)除去根的行和列之后的矩阵的行列式值。。。
而每次交换两行都要把答案乘上-1.
#include<bits/stdc++.h> #define ll long long const int ha=1000000007; using namespace std; char s[55][55]; int d[55],n,m; int a[55][55]; bool v[55]; ll matrix[55][55],ans=1; inline void spfa(){ queue<int> q; memset(d,0x3f,sizeof(d)); q.push(1),v[1]=1,d[1]=0; int x; while(!q.empty()){ x=q.front(),q.pop(),v[x]=0; for(int i=1;i<=n;i++) if(a[x][i]) if(d[x]+a[x][i]<d[i]){ d[i]=d[x]+a[x][i]; if(!v[i]) v[i]=1,q.push(i); } } } inline void xy(){ for(int i=2;i<=n;i++){ int tmp=0; for(int j=i;j<=n;j++) if(matrix[j][i]){ tmp=j; break; } if(!tmp) return; if(tmp>i){ ans=ha-ans; for(int j=i;j<=n;j++) swap(matrix[i][j],matrix[tmp][j]); } for(int j=i+1;j<=n;j++) if(matrix[j][i]){ int A; while(matrix[j][i]){ A=matrix[i][i]/matrix[j][i]; ans=ha-ans; for(int k=i;k<=n;k++){ matrix[i][k]=((ll)matrix[i][k]-A*(ll)matrix[j][k])%ha; if(matrix[i][k]<0) matrix[i][k]+=ha; swap(matrix[j][k],matrix[i][k]); } } } } } int main(){ cin>>n; for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=s[i][j]-'0'; spfa(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(a[i][j]&&d[i]+a[i][j]==d[j]){ matrix[j][j]++; matrix[i][j]--; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(matrix[i][j]<0) matrix[i][j]+=ha; xy(); for(int i=2;i<=n;i++) ans=ans*(ll)matrix[i][i]%ha; cout<<ans<<endl; return 0; }