河南省第二届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 }
原文地址:https://www.cnblogs.com/hxsyl/p/3043678.html