河南省第二届ACM程序设计大赛解题报告(置换群)

1.

 1 /*

 2 前两道题一直在纠结提议,特别是第二题,看了别人的代码才明白过来题意,由测试用例都没明白 

 3 */

 4 #include <iostream>

 5 #include <cstring>

 6 #include <queue>

 7 using namespace std;

 8 

 9 const int maxn = 55;

10 int ins[maxn];

11 bool vis[maxn] = {false};

12 int N,A,B;

13 

14 //假设边界在AB之间 

15 int solve()

16 {

17     /*

18     刚开始忘记了开标记数组,要保证每个节点只访问一次,否则会死循环 

19     */

20     int a = max(A,B);

21     int b = min(A,B);

22     queue <int > q;

23     int cnt = 0;

24     while(!q.empty())

25         q.pop();

26     q.push(A);

27     vis[A] = true;

28     bool flag = false;

29     while(!q.empty())

30     {

31         cnt++;

32         int head = q.front();

33         q.pop();

34         int left = head - ins[head];

35         int right = head + ins[head];

36         if(left>=b&&!vis[left])

37         {

38             if(left==B)

39             {

40                 flag = true;

41                 break; 

42             }

43             vis[left] = true;

44             q.push(left);

45         }

46         if(right<=a&&!vis[right])

47         {

48             if(right==B)

49             {

50                 flag = true;

51                 break; 

52             }

53             vis[right] = true;

54             q.push(right);

55         }

56     }

57     if(flag)

58         return cnt; 

59     else

60         return -1;     

61 }

62 

63 int main()

64 {

65     int i,j,k;

66     int M;

67     

68     cin>>M;

69     while(M--)

70     {

71         memset(vis,false,sizeof(vis));

72         memset(ins,0,sizeof(ins));

73         

74         cin>>N>>A>>B;

75         for(i=1; i<=N; i++)

76         {

77             cin>>ins[i];

78         }

79         int ans = solve();

80         cout<<ans<<endl;

81     }

82     return 0;

83     

84 }

2.刚开始用list写的,太恶心了,写不成,就换成直接的链表了
  

 1 #include <iostream>

 2 #include <cstring>

 3 using namespace std;

 4 

 5 int N,K;

 6 typedef struct Node 

 7 {

 8     int data;

 9     Node * next;

10 }Node;

11 

12 Node *head;

13 void init()

14 {

15     //头结点也要申请空间 

16     head = new Node;

17     head->data = 0;

18     head->next = NULL;

19     //头插法 

20     for(int i=1; i<=N; i++)

21     {

22         Node *p = new Node;

23         p->next = head->next;

24         head->next = p;

25         p->data = N-i+1;

26     }   

27 }

28 

29 int main()

30 {

31     int i,j,k;

32     cin>>N>>K;

33     int a,b,c;

34     init();

35     for(i=1; i<=K; i++)

36     {

37         cin>>a>>b>>c;

38         Node *p,*q,*r;

39         Node *temp1, *temp2, *temp3;

40         

41         int cnt = 0;

42         for(p=head; cnt<a-1; cnt++,p=p->next);

43         temp1 = p;

44         

45         cnt = 0;

46         for(p=head; cnt<b; cnt++,p=p->next);

47         temp2 = p;

48         

49         cnt = 0;

50         for(p=head; cnt<c; cnt++,p=p->next);

51         temp3 = p;

52         

53         Node *temp4 = temp2->next;

54         temp2->next = temp3->next;

55         temp3->next = temp1->next;

56         temp1->next = temp4;

57     }

58     Node *p;

59     int cnt = 0;

60     for(p=head->next,cnt=0; cnt<10; cnt++,p=p->next)

61     {

62         cout<<p->data<<endl;

63         

64     }

65     while(1);

66     return 0;

67 }

3.

4.参考华杰做出来的  

 

 1 //置换群问题 

 2 /*

 3 求最小费用时求较小着:用分解后的每个循环里的最小值,或者全局最小值 

 4 */

 5 #include <iostream>

 6 #include <cstring>

 7 #include <cstdlib>

 8 #include <algorithm>

 9 using namespace std;

10 

11 const int maxn = 1010;

12 int N;

13 int g_min = 1010;//全局置换群最小值,题目上说最大高度是1000 ,每次的全局最小会改变,不能是const 

14 

15 int hash[maxn],a[maxn],b[maxn];

16 bool vis[maxn];

17 

18 int solve()

19 {

20     memset(vis,false,sizeof(vis)); 

21     int i,j,k;

22     //若分解后的循环里面只有一个元素,则该元素在原来的群里面必定是排好序的

23     int len = N;

24     int l_min = 1010;//局部最小值 

25     int ans = 0;

26     while(len>0)

27     {

28         int i = 0;

29         int length = 0;//循环的长度 

30         //vis数组标记的是输入的顺序,先找到第一个后,那么经过下面的操作后第一个循环就被全部标记过了 

31         while(vis[i])

32         {

33             i++;

34         }

35         int begin = i;

36         int sum = 0;//每次循环的所有元素和 

37         //找循环

38         /*

39         必须用 do while(至少执行一次),或者死循环里用break;不可while(i!=begin)这样的话 因为int begin = i则大循环一直执行 

40         */

41         do

42         {

43             length++;

44             vis[i] = true;//i是个下标值 ,放在i改变之前                

45             if(l_min>a[i])

46                 l_min = a[i]; 

47             sum += a[i];

48             //hash数组返回的只是一个下标值 

49             i = hash[b[i]];//返回的是起点对应的下标所对应元素的下标 ,必须放在sum之后 

50         }while(begin!=i);

51         

52         len -= length;//必须在continue之前 

53         if(length==1)//必须有 ,表示循环里只有一个元素,则不花费代价 

54             continue;

55                   

56         //ans1用的是循环内最小值,sum存的是循环内所有的元素和 ,局部最小元素用了 (length-1)次,其他的用了一次,因为在sum

57         //里已经加了一次局部最小,所以 length-2)*l_min;

58         int ans1 = sum + (length-2)*l_min;

59         //全局的先把局部的换出来最后还要在换回来 ,所以答案是两次全局 + 两次局部 + sum里除了局部之外的其他元素和 

60         int ans2 = sum + l_min + (length+1)*g_min;

61         

62         ans += ans1>ans2?ans2:ans1;//是累计,不是直接赋值 

63     }

64     return ans;    

65 }

66 

67 int main()

68 {

69     int i,j,k;

70     int T;

71     cin>>T;

72     while(T--)

73     {

74         cin>>N;

75         memset(hash,0,sizeof(hash));

76         memset(a,0,sizeof(a));

77         memset(b,0,sizeof(b));

78       

79         

80         for(i=0; i<N; i++)

81         {

82             cin>>a[i];

83             b[i] = a[i];//排好序的数组 

84             if(g_min>a[i])

85             {

86                 g_min = a[i];

87             }

88             hash[a[i]] = i;

89         }

90         sort(b,b+N);

91         int ans = solve();

92         cout<<ans<<endl; 

93     }

94     system("pause");

95     return 0;

96 }

 

你可能感兴趣的:(程序设计)