zoukankan      html  css  js  c++  java
  • 最小生成树计数

    Minimum Spanning Tree http://acm.hdu.edu.cn/showproblem.php?pid=4408

    模板题

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #include<stack>
      5 #include<algorithm>
      6 #define mt(a,b) memset(a,b,sizeof(a))
      7 using namespace std;
      8 typedef __int64 LL;
      9 class MinST_count { ///最小生成树计数o(~=MV^3)+o(MElogME)
     10     typedef int typec;///边权的类型
     11     typedef LL typer;///返回值类型
     12     static const int ME=1024;///边的个数
     13     static const int MV=128;///点的个数
     14     struct E {
     15         int u,v;
     16         typec w;
     17         friend bool operator <(E a,E b) {
     18             return a.w<b.w;
     19         }
     20     } e[ME];
     21     typer mod,ans,mat[MV][MV];
     22     int n,le,fa[MV],ka[MV],gk[MV][MV];
     23     bool vis[MV];
     24     vector<int> gra[MV];
     25     int getroot(int a,int b[]) {
     26         return a==b[a]?a:b[a]=getroot(b[a],b);
     27     }
     28     typer det(typer a[][MV],int n) { ///生成树计数
     29         for(int i=0; i<n; i++)
     30             for(int j=0; j<n; j++)
     31                 a[i][j]%=mod;
     32         typer ret=1;
     33         for(int i=1; i<n; i++) {
     34             for(int j=i+1; j<n; j++) {
     35                 while(a[j][i]) {
     36                     typer t=a[i][i]/a[j][i];
     37                     for(int k=i; k<n; k++)
     38                         a[i][k]=(a[i][k]-a[j][k]*t)%mod;
     39                     for(int k=i; k<n; k++)
     40                         swap(a[i][k],a[j][k]);
     41                     ret=-ret;
     42                 }
     43             }
     44             if(!a[i][i]) return 0;
     45             ret=ret*a[i][i]%mod;
     46         }
     47         return (ret+mod)%mod;
     48     }
     49 public:
     50     void init(int tn,int tmod) { ///传入点的个数,%tmod,点下标1开始
     51         n=tn;
     52         mod=tmod;
     53         le=0;
     54         mt(fa,0);
     55         mt(ka,0);
     56         mt(vis,0);
     57         mt(gk,0);
     58         mt(mat,0);
     59     }
     60     void add(int u,int v,typec w) {
     61         e[le].u=u;
     62         e[le].v=v;
     63         e[le].w=w;
     64         le++;
     65     }
     66     typer solve() {///返回生成树个数%mod
     67         sort(e,e+le);
     68         for(int i=1; i<=n; i++) {
     69             fa[i]=i;
     70             vis[i]=false;
     71             gra[i].clear();
     72         }
     73         typec pre=-1;
     74         ans=1;
     75         for(int h=0; h<=le; h++) {
     76             if(e[h].w!=pre||h==le) { ///一组边加完
     77                 for(int i=1; i<=n; i++) {
     78                     if(vis[i]) {
     79                         int u=getroot(i,ka);
     80                         gra[u].push_back(i);
     81                         vis[i]=false;
     82                     }
     83                 }
     84                 for(int i=1; i<=n; i++) { ///枚举每个联通分量
     85                     if(gra[i].size()>1) {
     86                         mt(mat,0);
     87                         int len=gra[i].size();
     88                         for(int a=0; a<len; a++) { ///构建矩阵
     89                             for(int b=a+1; b<len; b++) {
     90                                 typer la=gra[i][a],lb=gra[i][b];
     91                                 mat[a][b]=(mat[b][a]-=gk[la][lb]);
     92                                 mat[a][a]+=gk[la][lb];
     93                                 mat[b][b]+=gk[la][lb];
     94                             }
     95                         }
     96                         typer ret=(typer)det(mat,len);
     97                         ans=(ans*ret)%mod;
     98                         for(int a=0; a<len; a++)
     99                             fa[gra[i][a]]=i;
    100                     }
    101                 }
    102                 for(int i=1; i<=n; i++) {
    103                     ka[i]=fa[i]=getroot(i,fa);
    104                     gra[i].clear();
    105                 }
    106                 if(h==le)break;
    107                 pre=e[h].w;
    108             }
    109             int a=e[h].u;
    110             int b=e[h].v;
    111             int pa=getroot(a,fa);
    112             int pb=getroot(b,fa);
    113             if(pa==pb)continue;
    114             vis[pa]=vis[pb]=true;
    115             ka[getroot(pa,ka)]=getroot(pb,ka);
    116             gk[pa][pb]++;
    117             gk[pb][pa]++;
    118         }
    119         for(int i=2; i<=n&&ans; i++)
    120             if(ka[i]!=ka[i-1])
    121                 ans=0;
    122         ans=(ans+mod)%mod;
    123         return ans;
    124     }
    125 } gx;
    126 int main(){
    127     int n,m,p,u,v,w;
    128     while(~scanf("%d%d%d",&n,&m,&p),n|m|p){
    129         gx.init(n,p);
    130         while(m--){
    131             scanf("%d%d%d",&u,&v,&w);
    132             gx.add(u,v,w);
    133         }
    134         printf("%I64d
    ",gx.solve());
    135     }
    136     return 0;
    137 }
    View Code

    1016: [JSOI2008]最小生成树计数 http://www.lydsy.com/JudgeOnline/problem.php?id=1016

    一样

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #include<stack>
      5 #include<algorithm>
      6 #define mt(a,b) memset(a,b,sizeof(a))
      7 using namespace std;
      8 class MinST_count { ///最小生成树计数o(~=MV^3)+o(MElogME)
      9     typedef int typec;///边权的类型
     10     typedef int typer;///返回值类型
     11     static const int ME=1024;///边的个数
     12     static const int MV=128;///点的个数
     13     struct E {
     14         int u,v;
     15         typec w;
     16         friend bool operator <(E a,E b) {
     17             return a.w<b.w;
     18         }
     19     } e[ME];
     20     typer mod,ans,mat[MV][MV];
     21     int n,le,fa[MV],ka[MV],gk[MV][MV];
     22     bool vis[MV];
     23     vector<int> gra[MV];
     24     int getroot(int a,int b[]) {
     25         return a==b[a]?a:b[a]=getroot(b[a],b);
     26     }
     27     typer det(typer a[][MV],int n) { ///生成树计数
     28         for(int i=0; i<n; i++)
     29             for(int j=0; j<n; j++)
     30                 a[i][j]%=mod;
     31         typer ret=1;
     32         for(int i=1; i<n; i++) {
     33             for(int j=i+1; j<n; j++) {
     34                 while(a[j][i]) {
     35                     typer t=a[i][i]/a[j][i];
     36                     for(int k=i; k<n; k++)
     37                         a[i][k]=(a[i][k]-a[j][k]*t)%mod;
     38                     for(int k=i; k<n; k++)
     39                         swap(a[i][k],a[j][k]);
     40                     ret=-ret;
     41                 }
     42             }
     43             if(!a[i][i]) return 0;
     44             ret=ret*a[i][i]%mod;
     45         }
     46         return (ret+mod)%mod;
     47     }
     48 public:
     49     void init(int tn,int tmod) { ///传入点的个数,%tmod,点下标1开始
     50         n=tn;
     51         mod=tmod;
     52         le=0;
     53         mt(fa,0);
     54         mt(ka,0);
     55         mt(vis,0);
     56         mt(gk,0);
     57         mt(mat,0);
     58     }
     59     void add(int u,int v,typec w) {
     60         e[le].u=u;
     61         e[le].v=v;
     62         e[le].w=w;
     63         le++;
     64     }
     65     typer solve() {///返回生成树个数%mod
     66         sort(e,e+le);
     67         for(int i=1; i<=n; i++) {
     68             fa[i]=i;
     69             vis[i]=false;
     70             gra[i].clear();
     71         }
     72         typec pre=-1;
     73         ans=1;
     74         for(int h=0; h<=le; h++) {
     75             if(e[h].w!=pre||h==le) { ///一组边加完
     76                 for(int i=1; i<=n; i++) {
     77                     if(vis[i]) {
     78                         int u=getroot(i,ka);
     79                         gra[u].push_back(i);
     80                         vis[i]=false;
     81                     }
     82                 }
     83                 for(int i=1; i<=n; i++) { ///枚举每个联通分量
     84                     if(gra[i].size()>1) {
     85                         mt(mat,0);
     86                         int len=gra[i].size();
     87                         for(int a=0; a<len; a++) { ///构建矩阵
     88                             for(int b=a+1; b<len; b++) {
     89                                 typer la=gra[i][a],lb=gra[i][b];
     90                                 mat[a][b]=(mat[b][a]-=gk[la][lb]);
     91                                 mat[a][a]+=gk[la][lb];
     92                                 mat[b][b]+=gk[la][lb];
     93                             }
     94                         }
     95                         typer ret=(typer)det(mat,len);
     96                         ans=(ans*ret)%mod;
     97                         for(int a=0; a<len; a++)
     98                             fa[gra[i][a]]=i;
     99                     }
    100                 }
    101                 for(int i=1; i<=n; i++) {
    102                     ka[i]=fa[i]=getroot(i,fa);
    103                     gra[i].clear();
    104                 }
    105                 if(h==le)break;
    106                 pre=e[h].w;
    107             }
    108             int a=e[h].u;
    109             int b=e[h].v;
    110             int pa=getroot(a,fa);
    111             int pb=getroot(b,fa);
    112             if(pa==pb)continue;
    113             vis[pa]=vis[pb]=true;
    114             ka[getroot(pa,ka)]=getroot(pb,ka);
    115             gk[pa][pb]++;
    116             gk[pb][pa]++;
    117         }
    118         for(int i=2; i<=n&&ans; i++)
    119             if(ka[i]!=ka[i-1])
    120                 ans=0;
    121         ans=(ans+mod)%mod;
    122         return ans;
    123     }
    124 } gx;
    125 int main(){
    126     int n,m,u,v,w;
    127     while(~scanf("%d%d",&n,&m)){
    128         gx.init(n,31011);
    129         while(m--){
    130             scanf("%d%d%d",&u,&v,&w);
    131             gx.add(u,v,w);
    132         }
    133         printf("%d
    ",gx.solve());
    134     }
    135     return 0;
    136 }
    View Code

    Lightning http://acm.hdu.edu.cn/showproblem.php?pid=4305

    首先是根据两点的距离不大于R,而且中间没有点建立一个图。之后就是求生成树计数了。需要强调的是计算几何部分用double来做超时,计数部分用long long也超时,全用int才能过。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<vector>
      6 #define mt(a,b) memset(a,b,sizeof(a))
      7 #define zero(x) (((x)>0?(x):-(x))<eps)
      8 using namespace std;
      9 const double eps=1e-8;
     10 struct point {
     11     int x,y;
     12 } p[310];
     13 int Distance2(point p1,point p2) {
     14     return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
     15 }
     16 int xmult(point p1,point p2,point p0) {
     17     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
     18 }
     19 int dot_online_in(point p,point l1,point l2) {
     20     return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;
     21 }
     22 int n,R;
     23 bool check(int k1,int k2) { ///判断两点的距离小于等于R,而且中间没有点阻隔
     24     if(Distance2(p[k1],p[k2]) > R*R)return false;
     25     for(int i = 0; i < n; i++)
     26         if(i!=k1 && i!=k2)
     27             if(dot_online_in(p[i],p[k1],p[k2]))
     28                 return false;
     29     return true;
     30 }
     31 class MinST_count { ///最小生成树计数o(~=MV^3)+o(MElogME)
     32     typedef int typec;///边权的类型
     33     typedef int typer;///返回值类型
     34     static const int ME=90010;///边的个数
     35     static const int MV=310;///点的个数
     36     struct E {
     37         int u,v;
     38         typec w;
     39         friend bool operator <(E a,E b) {
     40             return a.w<b.w;
     41         }
     42     } e[ME];
     43     typer mod,ans,mat[MV][MV];
     44     int n,le,fa[MV],ka[MV],gk[MV][MV];
     45     bool vis[MV];
     46     vector<int> gra[MV];
     47     int getroot(int a,int b[]) {
     48         return a==b[a]?a:b[a]=getroot(b[a],b);
     49     }
     50     typer det(typer a[][MV],int n) { ///生成树计数
     51         for(int i=0; i<n; i++)
     52             for(int j=0; j<n; j++)
     53                 a[i][j]%=mod;
     54         typer ret=1;
     55         for(int i=1; i<n; i++) {
     56             for(int j=i+1; j<n; j++) {
     57                 while(a[j][i]) {
     58                     typer t=a[i][i]/a[j][i];
     59                     for(int k=i; k<n; k++)
     60                         a[i][k]=(a[i][k]-a[j][k]*t)%mod;
     61                     for(int k=i; k<n; k++)
     62                         swap(a[i][k],a[j][k]);
     63                     ret=-ret;
     64                 }
     65             }
     66             if(!a[i][i]) return 0;
     67             ret=ret*a[i][i]%mod;
     68         }
     69         return (ret+mod)%mod;
     70     }
     71 public:
     72     void init(int tn,int tmod) { ///传入点的个数,%tmod,点下标1开始
     73         n=tn;
     74         mod=tmod;
     75         le=0;
     76         mt(fa,0);
     77         mt(ka,0);
     78         mt(vis,0);
     79         mt(gk,0);
     80         mt(mat,0);
     81     }
     82     void add(int u,int v,typec w) {
     83         e[le].u=u;
     84         e[le].v=v;
     85         e[le].w=w;
     86         le++;
     87     }
     88     typer solve() {///返回生成树个数%mod
     89         sort(e,e+le);
     90         for(int i=1; i<=n; i++) {
     91             fa[i]=i;
     92             vis[i]=false;
     93             gra[i].clear();
     94         }
     95         typec pre=-1;
     96         ans=1;
     97         for(int h=0; h<=le; h++) {
     98             if(e[h].w!=pre||h==le) { ///一组边加完
     99                 for(int i=1; i<=n; i++) {
    100                     if(vis[i]) {
    101                         int u=getroot(i,ka);
    102                         gra[u].push_back(i);
    103                         vis[i]=false;
    104                     }
    105                 }
    106                 for(int i=1; i<=n; i++) { ///枚举每个联通分量
    107                     if(gra[i].size()>1) {
    108                         mt(mat,0);
    109                         int len=gra[i].size();
    110                         for(int a=0; a<len; a++) { ///构建矩阵
    111                             for(int b=a+1; b<len; b++) {
    112                                 typer la=gra[i][a],lb=gra[i][b];
    113                                 mat[a][b]=(mat[b][a]-=gk[la][lb]);
    114                                 mat[a][a]+=gk[la][lb];
    115                                 mat[b][b]+=gk[la][lb];
    116                             }
    117                         }
    118                         typer ret=(typer)det(mat,len);
    119                         ans=(ans*ret)%mod;
    120                         for(int a=0; a<len; a++)
    121                             fa[gra[i][a]]=i;
    122                     }
    123                 }
    124                 for(int i=1; i<=n; i++) {
    125                     ka[i]=fa[i]=getroot(i,fa);
    126                     gra[i].clear();
    127                 }
    128                 if(h==le)break;
    129                 pre=e[h].w;
    130             }
    131             int a=e[h].u;
    132             int b=e[h].v;
    133             int pa=getroot(a,fa);
    134             int pb=getroot(b,fa);
    135             if(pa==pb)continue;
    136             vis[pa]=vis[pb]=true;
    137             ka[getroot(pa,ka)]=getroot(pb,ka);
    138             gk[pa][pb]++;
    139             gk[pb][pa]++;
    140         }
    141         for(int i=2; i<=n&&ans; i++)
    142             if(ka[i]!=ka[i-1])
    143                 ans=0;
    144         ans=(ans+mod)%mod;
    145         return ans;
    146     }
    147 } gx;
    148 int main() {
    149     int T;
    150     scanf("%d",&T);
    151     while(T--) {
    152         scanf("%d%d",&n,&R);
    153         for(int i = 0; i < n; i++){
    154             scanf("%d%d",&p[i].x,&p[i].y);
    155         }
    156         gx.init(n,10007);
    157         for(int i = 0; i < n; i++)
    158             for(int j = i+1; j <n; j++)
    159                 if(check(i,j))
    160                     gx.add(i+1,j+1,1);
    161         int ans=gx.solve();
    162         if(!ans) ans=-1;
    163         printf("%d
    ",ans);
    164     }
    165     return 0;
    166 }
    View Code

    end

  • 相关阅读:
    thinkphp的钩子的两种配置和两种调用方法
    php闭包实现函数的自调用,也是递归
    php的spl_autoload_register函数的一点个人见解
    详解js变量、作用域及内存
    关于js的call()和apply()两个函数的一点个人看法
    php实现斐波那契数列以及由此引起的联想
    php猴子称王或者约瑟夫难题
    Linux Bash Shell 快速入门
    Fedora14下首次搭建Samba服务器遇到的一些问题
    【JavaScript】我的JavaScript技术总结第一篇——编程细节
  • 原文地址:https://www.cnblogs.com/gaolzzxin/p/3944788.html
Copyright © 2011-2022 走看看