UVA 10294 poj 3270 置换问题
2016-04-07 19:34
417 查看
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=35397
点击打开链接
解析见 算法入门经典训练指南:
Burnside定理:对于一个置换f,若一个方案s经过置换后不变,则s为一个不动点。一个置换f的不动点数目为C(f),则等价类数目为C(f)的平均值。
Polya定理:置换f可以分解成m(f)个循环的乘积,有k种涂色方案,等价类的个数等于所有置换f的k^m(f)的平均数
题目:有一串数字,要将它排列成升序,每次可以交换两个数,交换一次的代价为两数之和。要求代价最小。
点击打开链接
例如初始状态为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
点击打开链接
解析见 算法入门经典训练指南:
Burnside定理:对于一个置换f,若一个方案s经过置换后不变,则s为一个不动点。一个置换f的不动点数目为C(f),则等价类数目为C(f)的平均值。
Polya定理:置换f可以分解成m(f)个循环的乘积,有k种涂色方案,等价类的个数等于所有置换f的k^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; } } }
相关文章推荐
- SPI总线的特点、工作方式介绍
- hdu4975A simple Gaussian elimination problem.【网络流判断是否解唯一】
- 顺序结构存储串实现串通配符匹配的算法
- 剑指offer-面试题6.重建二叉树
- 第七周一周总结
- spring 配置文件中的占位符 使用 context:property-placeholder
- Java Script之创建对象
- 博弈论的总结
- 技术贴
- 功夫茶侠(品茗)
- UESTC第十四届校赛A题解题报告
- Manifest merger failed : Attribute application@label value=(@string/app_name)
- oracle数据库归档日志文件管理常用命令
- GDAL创建图像提示Driver xxx does not support XXX creation option的原因
- Java基础知识
- POJ2236Wireless Network
- bzoj 1715(spfa 判断负环)
- GDAL创建图像提示Driver xxx does not support XXX creation option的原因
- DCOS之Mesos-DNS介绍
- 剑指offer-面试题5.从尾到头打印链表