UVA 10294 poj 3270 置换问题

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=35397

点击打开链接


解析见 算法入门经典训练指南:



Burnside定理:对于一个置换f,若一个方案s经过置换后不变,则s为一个不动点。一个置换f的不动点数目为Cf),则等价类数目为Cf)的平均值。

Polya定理:置换f可以分解成m(f)个循环的乘积,有k种涂色方案,等价类的个数等于所有置换fk^m(f)的平均数



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int n,t;
    while(cin>>n>>t)
    {
        LL a=0;
        for(int i=0;i<=n-1;i++)
            a+=pow(t,gcd(i,n));
        LL b=0;
        if(n%2)
            b=n*pow(t,(n+1)/2);
        else
            b=n/2*(pow(t,n/2+1)+pow(t,n/2));
        cout<<a/n<<" "<<(a+b)/(2*n)<<endl;
    }
    return 0;
}

题目:有一串数字,要将它排列成升序,每次可以交换两个数,交换一次的代价为两数之和。要求代价最小。

点击打开链接

例如初始状态为1 8 9 7 6 目标状态为 1 6 7 8 9,可以分解为 (1)(8 6 9 7)第一个循环只有一个元素,证明它在正确的位置,不参与计算,
第二个循环如果按第一种方法来的话,花费为 6+7+8+9+(4-2)*6=42  而第二种花费为 6+7+8+9+6+(4+1)*1=41

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 99999999
using namespace std;
struct node
{
    int id;
    int num;
}p[10010];
bool visited[10010];
bool cmp(struct node a,struct node b)
{
    return a.num<b.num;
}
int main()
{
    int n;
    cin>>n;
    int minx=inf;
    for(int i=0;i<=n-1;i++)
    {
        cin>>p[i].num;
        p[i].id=i;
        if(p[i].num<minx)
            minx=p[i].num;
    }
    sort(p,p+n,cmp);
    memset(visited,0,sizeof(visited));
    int ans=0;
    for(int i=0;i<=n-1;i++)//访问循环模板
    {
        if(!visited[i])
        {
            int cnt=1;
            visited[i]=1;
            int sum=p[i].num;
            int l=p[i].id;
            int minxx=p[i].num;
            while(l!=i)
            {
                cnt++;
                visited[l]=1;
                sum+=p[l].num;
                l=p[l].id;
                if(minxx>p[l].num)
                    minxx=p[l].num;
            }
            ans+=min(sum-minxx+(cnt-1)*minxx,sum+(cnt+1)*minx+minxx);
        }
    }
    cout<<ans<<endl;
    return 0;
}


统计各个循环中的数据模板

struct node
{
    int id;//位置
    int num;//数
}p[10010];
sort后的序列为新序列
memset(visited,0,sizeof(visited));
    for(int i=0;i<=n-1;i++)//访问循环模板
    {
        if(!visited[i])
        {
            int cnt=1;//统计循环的点个数
            visited[i]=1;
            int sum=p[i].num;//统计循环的数之和
            int l=p[i].id;
            int minxx=p[i].num;//寻找循环中的最小值
            while(l!=i)
            {
                cnt++;
                visited[l]=1;
                sum+=p[l].num;
                l=p[l].id;
                if(minxx>p[l].num)
                    minxx=p[l].num;
            }
        }
    }

你可能感兴趣的:(UVA 10294 poj 3270 置换问题)