hdu4305Matrix-Tree理论

传送门
题意:N个机器人在那站着,一天打雷霹到一个机器人,那么距离他小于R以内的机器人都会被霹到,但是三点共线的情况只能传染最近的那个,问最后闪电击中形成的形状有多少种,也就是求无向图生成树个数。
求生成树个数问题最好的方法是Matrix-Tree定理。
Matrix-Tree定理
一,
对于无向图A表示其邻接矩阵,B表示其度数矩阵,Kirchhoff矩阵H=B-A
简单的来说可以这么表示,
当 i!=j 时且A[i][j]==1, H[i][j]=-1,
当i==j时,H[i][j]=i的度数。举例。
取自《欧拉回路与生成树关系》
那么其Kirchhoff矩阵就是右边的矩阵。
那么该图生成树个数=H的任意一个代数余子式
二,
对于有向图的Krichhoff矩阵 H[i][j]有所不同;
当i!=j H[i][j]=顶点 j到顶点i的路径条数
当i==j H[]i[j]=顶点i的入度
而其生成树个数与根节点有关,以i点为根的生成树个数=去除i行i列的代数余子式。(因为矩阵一定是V*V的方阵,i点位于i行j列,i==j,所以称为i行i列)
所以求有向图的生成树个数要枚举所有点(根)。
三,
本题呢,肯定是无向图啦,枚举所有点求出每个点之间的距离,把距离小于R的且两点之间不含有其他点的 两个点连接形成一条边,得到邻接矩阵A,那么Krichhoff矩阵唾手可得。
然后求任意一个代数余子式即可。代数余子式用模板求一下就行了。
模板:

LL inv(LL a,LL m)///逆元
{
    if(a==1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}
struct Matrix
{
    LL mat[MAXN][MAXN];
    void init()
    {
        memset(mat,0,sizeof(mat));
    }
    LL det(int n)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                mat[i][j]=(mat[i][j]%MOD+MOD)%MOD;
        LL res=1;
        for(int i=0; i<n; i++)
        {
            for(int j=i; j<n; j++)
            {
                if(mat[i][j]!=0)
                {
                    for(int k=i; k<n; k++)
                        swap(mat[i][k],mat[j][k]);
                    if(i!=j)
                        res=(-res+MOD)%MOD;
                    break;
                }
            }
            if(mat[i][i]==0)
            {
                res=0;///不存在,行列式为0
                break;
            }
            for(int j=i+1; j<n; j++)
            {
                int mut=(mat[j][i]*inv(mat[i][i],MOD))%MOD;
                for(int k=i; k<n; k++)
                    mat[j][k]=(mat[j][k]-(mat[i][k]*mut)%MOD+MOD)%MOD;
            }
            res=(res*mat[i][i])%MOD;
        }
        return res;
    }
};


        Matrix ret;
        ret.init();

        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i!=j&&g[i][j])
                {
                    ret.mat[i][j]=-1;
                    res.mat[i][i]++;
                }
            }
        }



本题代码:

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef long long LL;
using namespace std;
const int MOD=10007;
const int MAXN=305;
int R;
struct node
{
    int x,y;
}d[305];
int N;
int dis(int i,int j)
{
  return (d[i].x-d[j].x)*(d[i].x-d[j].x)+(d[i].y-d[j].y)*(d[i].y-d[j].y);
}
int ok(int i,int j)
{
    int temp=dis(i,j);
    if(temp>R*R)
        return 0;
    for(int k=0;k<N;k++)
    {
        if(k!=i&&k!=j)
        {
            if(dis(i,k)<temp
               &&dis(k,j)<temp&&
               (d[i].x-d[k].x)*(d[j].y-d[k].y)==(d[j].x-d[k].x)*(d[i].y-d[k].y))///叉积==0
                return 0;
        }
    }
    return 1;
}
LL inv(LL a,LL m)
{
    if(a==1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}
struct Matrix
{
    int mat[MAXN][MAXN];
    void init()
    {
        memset(mat,0,sizeof(mat));
    }
    int det(int n)
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            mat[i][j]=(mat[i][j]%MOD+MOD)%MOD;
        int res=1;
        for(int i=0;i<n;i++)
        {
            for(int j=i;j<n;j++)
            {
                if(mat[i][j]!=0)
                {
                    for(int k=i;k<n;k++)
                        swap(mat[i][k],mat[j][k]);
                    if(i!=j)
                        res=(-res+MOD)%MOD;
                    break;
                }
            }
            if(mat[i][i]==0)
            {
                res=-1;///不存在,行列式为0
                break;
            }
            for(int j=i+1;j<n;j++)
            {
                int mut=(mat[j][i]*inv(mat[i][i],MOD))%MOD;
                for(int k=i;k<n;k++)
                    mat[j][k]=(mat[j][k]-(mat[i][k]*mut)%MOD+MOD)%MOD;
            }
            res=(res*mat[i][i])%MOD;
        }
        return res;
    }
};
int G[MAXN][MAXN];
int main()
{
    int T,n;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&R);
        N=n;
        for(int i=0;i<n;i++)
            scanf("%d%d",&d[i].x,&d[i].y);
            Matrix Mat;
            Mat.init();
            memset(G,0,sizeof(G));
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                if(ok(i,j))
                G[i][j]=G[j][i]=1;
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(G[i][j]&&i!=j)
                {
                    Mat.mat[i][j]=-1;
                    Mat.mat[i][i]++;
                }
            }
        }
        cout<<Mat.det(n-1)<<endl;

    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值