SPOJ 104 HIGH - Highways(生成树计数 不取模)

题目链接:点击打开链接

   一个有n座城市的组成国家,城市1至n编号,其中一些城市之间可以修建高速公路。现在,需要有选择的修建一些高速公路,从而组成一个交通网络。你的任务是计算有多少种方案,使得任意两座城市之间恰好只有一条路径?

 可以将问题转化到成图论模型。因为任意两点之间恰好只有一条路径,所以我们知道最后得到的是原图的一颗生成树。因此,我们的问题就变成了,给定一个无向图G,求它生成树的个数t(G)。

裸的生成树计数 不取模  贴个板子(具体的可参考 周冬论文 生成树计数及其应用)

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#include <queue>

#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 110
#define MAXM 100010
#define INF 99999999
#define ll __int64
#define bug cout<<"here"<<endl
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)

using namespace std;

int Read()
{
    char ch;
    int a = 0;
    while((ch = getchar()) == ' ' | ch == '\n');
    a += ch - '0';
    while((ch = getchar()) != ' ' && ch != '\n')
    {
        a *= 10;
        a += ch - '0';
    }
    return a;
}

void Print(int a)
{
     if(a>9)
         Print(a/10);
     putchar(a%10+'0');
}

int sgn(double x)
{
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    else return 1;
}
double b[MAXN][MAXN];
double det(double a[][MAXN],int n)
{
    int i,j,k,sign=0;
    double ret=1;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            b[i][j]=a[i][j];
    for(i=0;i<n;i++)
    {
        if(sgn(b[i][i])==0)
        {
            for(j=i+1;j<n;j++)
                if(sgn(b[j][i])!=0)
                    break;
            if(j==n) return 0;
            for(k=i;k<n;k++)
                swap(b[i][k],b[j][k]);
            sign++;
        }
        ret*=b[i][i];
        for(k=i+1;k<n;k++)
            b[i][k]/=b[i][i];
        for(j=i+1;j<n;j++)
            for(k=i+1;k<n;k++)
                b[j][k]-=b[j][i]*b[i][k];
    }
    if(sign&1) ret=-ret;
    return ret;
}
double a[MAXN][MAXN];
int g[MAXN][MAXN];

int main()
{
//    fread;
    int tc;
    scanf("%d",&tc);
    while(tc--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        MEM(g,0);
        while(m--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            u--; v--;
            g[u][v]=g[v][u]=1;
        }
        MEM(a,0);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(i!=j&&g[i][j])
        {
            a[i][i]++;
            a[i][j]=-1;
        }
        double ans=det(a,n-1);
        printf("%.0lf\n",ans);
    }
    return 0;
}
</span>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值