• 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;
    }
    

      

  • 相关阅读:
    Linq与Lambda,神一般的工作效率
    svn和git孰优孰劣
    关于C++的***5的输出问题
    POJ 3469 Dual Core CPU(最小割)
    HDU 4259 Double Dealing
    最大流Dinic算法
    HDU 4442 Physical Examination(2012年金华赛区现场赛A题)
    int ,long , long long类型的范围
    POJ 1679 The Unique MST(判断最小生成树是否唯一)
    HDU 4280 Island Transport(网络流)
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8504087.html
Copyright © 2020-2023  润新知