最小生成树计数

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\n",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\n",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\n",ans);
164     }
165     return 0;
166 }
View Code

 

end

转载于:https://www.cnblogs.com/gaolzzxin/p/3944788.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值