5056: OI游戏
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 204 Solved: 162
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2
01
10
Input2
4
0123
1012
2101
3210
Sample Output
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; }