题目链接:http://codeforces.com/problemset/problem/471/B
题目意思:有 n 个 tasks,编号依次为 1 ~ n,每个 task 都有一定的难度值来评估。例如,第 i 个 task 的难度值为 hi。现在的任务是把 n 个 task 全部完成,难度值越小的task越先完成。有3个人,都希望自己完成所有task的输出序列是与众不同的,问是否存在至少3条完成所有task的不同序列,没有的话输出 “NO”,否则输出“YES”并输出3条不同的完成序列。
昨晚比赛的题目,有一点点思路,但最终调不出来,泪~~。
小小的思路: 首先要知道有解的情况是什么。当时想到的是:两种情况。(1)相同难度值(difficulty)的task 至少有3个,类似这种序列:1 2 3 3 3 5 (2)相同 difficulty 的 task 有2个,但这种类型的task 至少有2个,类似这种序列: 1 2 2 4 4 5
不过处理起来确实复杂无比,甚至用到 vector 来存储每个难度值的邻接表,总的来说就是想得太复杂啦!!
看了下别人的代码,发现思路其实是没有错的,还算是有一点点欣慰 ^_^
首先判断是否能找到3条不同序列。用一个 used 数组来统计difficulty相同的task有多少个。处理的时候同常规办法有一点点不同,是先 used[h[i]] 再 count,但 used[h[i]]++在这条语句之后,这样处理的巧妙之处就是把我上面的两种情况都包括上去了,不用另外讨论。
另外,可以用pair<int, int> 来解决存储问题,first值保存task的difficulty,second值保存task的id。排序是很容易想到的,因为要按题目要求,难度值越少的task越先做嘛~~
最后一个问题就是,如何得到3条不同的序列,用 swap 可以解决。由于排序之后,对于相同difficulty的task,它们的 id 默认是从小到大排序的,那么swap 的条件是,对于相同difficulty 的task,交换那些 后面 id > 前面 id 的task。可以知道,每交换一次,就得到一条新的完成序列。
版本1(个人比较喜欢这个多点)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 #define f first 9 #define s second 10 typedef pair<int, int> pii; 11 12 const int maxn = 2000 + 10; 13 pii task[maxn]; 14 int used[maxn]; 15 16 int main() 17 { 18 int n; 19 // freopen("input.txt", "r", stdin); 20 while (scanf("%d", &n) != EOF) 21 { 22 int in, count = 0; 23 memset(used, 0, sizeof(used)); 24 for (int i = 1; i <= n; i++) 25 { 26 scanf("%d", &in); 27 task[i] = pii(in, i); // 巧妙的赋值 28 if (used[in]) 29 count++; 30 used[in]++; 31 } 32 if (count < 2) 33 printf("NO "); 34 else 35 { 36 printf("YES "); 37 sort(task+1, task+1+n); // 默认按pair first 排序 38 39 for (int time = 0; time < 3; time++) 40 { 41 for (int i = 1; i <= n; i++) 42 printf("%d ", task[i].s); 43 printf(" "); 44 45 for (int i = 1; i < n; i++) 46 { 47 if (task[i].f == task[i+1].f && task[i].s < task[i+1].s) 48 { 49 swap(task[i], task[i+1]); 50 break; 51 } 52 } 53 } 54 } 55 } 56 return 0; 57 }
版本2(比赛时死也调不出来,看了别人的在原来基础上改的)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 2000 + 10; 9 struct node{ 10 int id; 11 int h; 12 }task[maxn]; 13 14 int cmp(node a, node b) 15 { 16 return a.h < b.h; 17 } 18 19 int cnt[maxn]; 20 21 int main() 22 { 23 int n; 24 // freopen("input.txt", "r", stdin); 25 while (scanf("%d", &n) != EOF) 26 { 27 int t, c0 = 0; 28 bool flag = false; 29 memset(cnt, 0, sizeof(cnt)); 30 for (int i = 1; i <= n; i++) 31 { 32 scanf("%d", &t); 33 task[i].h = t; 34 task[i].id = i; 35 36 if (cnt[t]) // 同一个h值出现3次以上/两个以上的h值出现2次以上 37 c0++; 38 cnt[t]++; 39 } 40 if (c0 < 2) 41 printf("NO "); 42 else 43 { 44 printf("YES "); 45 sort(task+1, task+1+n, cmp); 46 for (int time = 0; time < 3; time++) 47 { 48 for (int i = 1; i <= n; i++) 49 printf("%d ", task[i].id); 50 printf(" "); 51 52 for (int i = 1; i < n; i++) 53 { 54 if (task[i].h == task[i+1].h && task[i].id < task[i+1].id) 55 { 56 swap(task[i], task[i+1]); 57 break; 58 } 59 } 60 } 61 } 62 } 63 return 0; 64 }