hdu 1443 Joseph

来源:互联网 发布:上海网络教育大学报名 编辑:程序博客网 时间:2024/05/21 11:15

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1443

该题题意是有2k个人围成一圈,前k个人为好人,后k个人为坏人,从第一个人开始报数,报数报到m时,该人退出此圈,现要求确定一个最小m的值使得所有坏人在任意一个好人之前全部出圈。

首先把这2k个人标号为0、1、2...2*k-1(标号从0开始而不从1开始有一个很大的好处,下面会提到)。显然每次报数标号为 (m-1)%total  (total为圈上总人数)的人要出圈,当

(m-1)%total==0时表示转了一圈回到第一个人(标号为0),此时若当初标号从1开始设置到2*k那么每次报数标号为m%total 的人要出圈,但是当m%total==0时表示的是刚好最后一个人必须出圈,这样出局号就与设置的标号不相对应,对该题后面的处理会造成很大的障碍!

然后是自己模拟出一个圈,先定义一个结构体

typedef struct joseph
{
int next;  //下一位圈上人的标号
int pre;  //上一位圈上人的标号
int cur;  //自己的标号
}joseph;

定义这样的结构体就把圈内每个人都连接了起来,相当于一个静态链表;当圈中一人需要出局时,就把该人前一个人的标号改为该人的所指的下一位人的标号,该人后一个人前指标号(即pre)改为该人前一位人的标号(有点拗口。。。不过其实很简单,与链表的删除操作基本一样),然后总人数减一,这样就模拟了约瑟夫环的过程。

最后就是把m从1开始循环直至有满足题目中让后面K人先出局的m值;以下是代码

#include<iostream>
using namespace std;
typedef struct joseph
{
int next;
int pre;
int cur;
}joseph;
int main()
{
int k,m,count,total,i,j,rec1,rec2,a[14];
joseph p[30];
count=0;
for(j=1;j<=13;j++)
{
for(m=2;count!=j*2;m++)
{
for(i=0;i<2*j;i++)
{
p[i].cur=i;
p[i].next=i+1;
p[i].pre=i-1;
}
p[2*j-1].next=p[0].cur;
p[0].pre=p[2*j-1].cur;                                  //将每个人连成环
count=0;
rec1=0;
total=2*j;
do
{
for(i=1;i<=(m-1)%total;i++)
rec1=p[rec1].next;
rec2=p[rec1].next;
p[p[rec1].pre].next=rec2;
p[rec2].pre=p[rec1].pre;                    //删除需要出圈者
if(p[rec1].cur>=0 && p[rec1].cur<j)  //出圈了好人,跳出该m值的循环
{
break;
}
else
{
rec1=rec2;
count++;                      //出圈一个坏人计数器加1 
}
total--;                                   //出圈一人后总人数记得减一
}while(count!=j);
if(count==j)                               //出圈好人前出圈完K个坏人,满足条件
{
a[j]=m;
break;
}
}
}
while(cin>>k && k)
{
cout<<a[k]<<endl;
}
return 0;
}

最后需要注意一点就是此题数据K不超过14,按照这种思路只能打表,给a数组赋值每种K值对应的m值答案,打表需要400+MS,不打表超时,所以该思路有待改进!


原创粉丝点击