HDU 5080 Colorful Toy(polya+计算几何)

来源:互联网 发布:软件压力测试工具 编辑:程序博客网 时间:2024/05/23 23:22

Description
给出n个整点的坐标以及这n个点之间连的m条边,现用c种颜色给这n个点染色,旋转后重合视为同一种方案,问一共有多少种不同的方案
Input
第一行为一整数表示用例组数T,每组用例第一行为三个整数n,m,c分别表示点数,边数以及颜色数,之后n行每行两个整数表示该点坐标,最后m行每行两个整数a,b表示点a和点b之间有一条边
(1<=T<=20,1<=n<=50,0<=m<=n*(n-1)/2,1<=c<=100)
Output
对于每组用例,输出染色方案数,结果模1e9+7
Sample Input
2
5 6 2
0 0
1 0
0 1
-1 0
0 -1
1 2
1 3
2 3
3 4
4 5
5 2
5 4 2
0 0
1 0
0 1
-1 0
0 -1
2 3
3 4
4 5
5 2
Sample Output
32
12
Solution
polya,首先暴力搞出置换的个数,由于是整点所以只有以图形中心旋转0度,90度,180度以及270度才可能为一种置换(为方便坐标转换可以将所有点的坐标都减去中心点的坐标使得中心点变成原点),暴力枚举这三种旋转(不转显然是一种置换),对于每种旋转求出旋转后的点的坐标,然后将这些点与原来的点一一对应(点相同),然后将原来点的关系矩阵映到新的点中再判断这两个关系矩阵是否相同(边相同),如果都相同则为一个置换,再根据原先点和旋转后点的映射关系求出轮换数,之后套polya定理即可
Code

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>using namespace std;#define maxn 55#define mod 1000000007#define eps 1e-4typedef long long ll;struct node{    double x,y;}p[maxn],tp[maxn];int T,n,m,c,M[maxn][maxn],tM[maxn][maxn],id[maxn],cnt;double x,y;ll ans;ll mod_pow(ll a,ll b,ll p){    ll ans=1ll;    a%=p;    while(b)    {        if(b&1) ans=(ans*a)%p;        a=(a*a)%p;        b>>=1;    }     return ans;}int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d%d%d",&n,&m,&c);        for(int i=0;i<maxn;i++)            for(int j=0;j<maxn;j++)M[i][j]=0;        x=y=0;        cnt=ans=1;        for(int i=0;i<n;i++)        {            scanf("%lf%lf",&p[i].x,&p[i].y);            x+=p[i].x,y+=p[i].y;        }        x/=n,y/=n;        for(int i=0;i<n;i++)p[i].x-=x,p[i].y-=y;//将图平移使得中心点是原点         while(m--)        {            int a,b;            scanf("%d%d",&a,&b);            a--,b--;            M[a][b]=M[b][a]=1;        }        for(int i=0;i<n;i++)ans=ans*c%mod;//不旋转         for(int k=1;k<4;k++)//旋转k*90度         {            int flag=1;            memset(id,0,sizeof(id));            for(int i=0;i<maxn;i++)                for(int j=0;j<maxn;j++)tM[i][j]=0;            //坐标转换             if(k==1)for(int i=0;i<n;i++)tp[i].x=-p[i].y,tp[i].y=p[i].x;            else if(k==2)for(int i=0;i<n;i++)tp[i].x=-p[i].x,tp[i].y=-p[i].y;            else if(k==3)for(int i=0;i<n;i++)tp[i].x=p[i].y,tp[i].y=-p[i].x;            for(int i=0;i<n&&flag;i++)//判断旋转后点的坐标与原先点是否能一一对应             {                int temp=0;                for(int j=0;j<n&&!temp;j++)                    if(fabs(p[j].x-tp[i].x)<eps&&fabs(p[j].y-tp[i].y)<eps)                        temp=1,id[j]=i;                if(!temp)flag=0;            }            for(int i=0;i<n;i++)//求出旋转后点的关系矩阵                 for(int j=0;j<n;j++)                    if(M[i][j])tM[id[i]][id[j]]=1;            for(int i=0;i<n;i++)//判断两个关系矩阵是否相同                 for(int j=0;j<n;j++)                    if(M[i][j]!=tM[i][j])flag=0;            if(flag)//合法置换             {                int res=0;                for(int i=0;i<n;i++)//求轮换数                 {                    if(id[i]==-1)continue;                    int j=i;                    while(id[j]!=i&&~j)                    {                        int temp=j;                        j=id[j],id[temp]=-1;                    }                    id[j]=-1;                    res++;                }                ll temp=1;                for(int i=0;i<res;i++)temp=temp*c%mod;                ans=(ans+temp)%mod;                cnt++;            }        }        ans=ans*mod_pow(cnt,mod-2,mod)%mod;        printf("%lld\n",ans);    }    return 0;} 
0 0