标签:
题意:n个点m条边,给边染色,有c种颜色,求染色方案有几种(旋转重合的方案记作同一种);
思路:旋转染色方案数用polya定理解决,每个置换群计算一次;
由计算几何的方法控制旋转,由sin,cos的有理数性质得,分别计算旋转0,90,180,270的方案数;
#pragma comment(linker,"/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define ll long long #define db double using namespace std; const int N=55; const db eps=1e-8; const db PI=acos(-1.0); const ll MOD=1000000007; int n,m,mp[N][N]; bool mk[N]; ll c; int sgn(db t){ return t<-eps?-1:t>eps; } ll inv(ll t){ //inv ll res=1,k=MOD-2; while(k){ if(k&1) res=(res*t)%MOD; t=(t*t)%MOD; k>>=1; } return res; } struct E{ int a,b; void input(){ scanf("%d%d",&a,&b); } }ed[N*N]; struct P{ db x,y; int id; void input(){ int xx,yy; scanf("%d%d",&xx,&yy); x=xx,y=yy; } P(db xx=0,db yy=0):x(xx),y(yy){} P rot(db thta){ //坐标转化 return P(x*cos(thta)-y*sin(thta),x*sin(thta)+y*cos(thta)); //不要忘记return!!! } P rotbyp(P center,db thta){ //绕中心旋转 P tmp(x-center.x,y-center.y); P ans=tmp.rot(thta); ans=ans+center; return ans; } P operator + (const P &t)const{ return P(x+t.x,y+t.y); } bool operator == (const P &t)const{ return sgn(x-t.x)==0&&sgn(y-t.y)==0; } }p[N],pb,np[N]; int pt[N]; ll g,ans; bool check(){ for(int i=0;i<m;i++){ int a=ed[i].a,b=ed[i].b; //每条边的两端 a=pt[a],b=pt[b]; if(mp[a][b]&&mp[b][a]); //是否连接 else return false; } return true; } bool fl[N]; int find_t(){ //不同的等价类的个数,循环节数 memset(fl,false,sizeof(fl)); int res=0; for(int i=0;i<n;i++){ if(!fl[i]){ res++; } int t=i; while(!fl[t]){ fl[t]=true; t=pt[t]; } } return res; } void dfs(int v){ if(v==n){ //波利亚计数 if(check()){ int t=find_t(); g++; ll res=1; for(int i=0;i<t;i++) res=res*c%MOD; ans=(ans+res)%MOD; } } else{ for(int i=0;i<n;i++){ if(!mk[i]&&(np[v]==p[i])){ //重合点,找到最后一个重合位置 mk[i]=true; pt[v]=i; dfs(v+1); mk[i]=false; } } } } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d%I64d",&n,&m,&c); pb.x=pb.y=0.0; for(int i=0;i<n;i++){ p[i].input(); p[i].id=i; pb.x+=p[i].x;pb.y+=p[i].y; } pb.x/=(db)n;pb.y/=(db)n; //中心 memset(mp,0,sizeof(mp)); for(int i=0;i<m;i++){ ed[i].input(); ed[i].a--;ed[i].b--; mp[ed[i].a][ed[i].b]=mp[ed[i].b][ed[i].a]=1; } //输入点和边 ans=g=0; memset(mk,false,sizeof(mk)); for(int i=0;i<4;i++){ //四个角度 for(int j=0;j<n;j++){ np[j]=p[j].rotbyp(pb,i*PI/2.0); //旋转后的点 } dfs(0); } printf("%lld\n",ans*inv(g)%MOD); } return 0; }
hdu 5080 Colorful Toy(计算几何+polya定理)
标签:
原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4781626.html