bzoj 5056: OI游戏

5056: OI游戏

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 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

Sample Output

Output1
1
Output2
6

HINT

 

Source

By 佚名上传

 

 

赤裸裸的矩阵树定理。

有向图的外向生成树个数=(入度矩阵-邻接矩阵)除去根的行和列之后的矩阵的行列式值。。。

而每次交换两行都要把答案乘上-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;
}

  

posted @ 2018-03-04 10:59  蒟蒻JHY  阅读(422)  评论(0编辑  收藏  举报