POJ - 3476 A Game with Colored Balls---优先队列+链表(用数组模拟)
题目链接:
https://cn.vjudge.net/problem/POJ-3476
题目大意:
一串长度为N的彩球,编号为1-N,每个球的颜色为R,G,B,给出它们的颜色,然后进行如下操作:
每次消除连续颜色最长的最左端的一串,剩下的球如果分成两串,就把左右两串连接起来,输出每次消除的球的颜色及编号。
解题思路:
将球的同一颜色的串压入优先队列中,每次取出最长的串,相同长度的串取最左端的串。
取出来之后,如果将小球分成了两串,如果两端颜色一样可以合并,那就网优先队列中压入新合成的串。每次取出串之后,将串的每一位进行标记,原因是由于没有将原来的两串删除就直接直接加入合并后的串,所以只需要标记一下已经取出,那么后加入的串由于长度长会先出优先队列。算法是正确的。
对于需要输出具体是那些小球,利用pre数组和next数组,pre[i]表示第i个小球前面连着的小球的下标。next则表示后面连着的小球,用这两个数组模拟双端链表,可以输出具体是那些小球。
用C++提交不会超时
1 //#include<bits/stdc++.h> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 const int maxn = 1e6 + 10; 7 typedef long long ll; 8 struct node 9 { 10 char c; 11 int pos, len; 12 node(char c, int pos, int len):c(c), pos(pos), len(len){} 13 bool operator <(const node& a)const 14 { 15 return len < a.len || len == a.len && pos > a.pos;//优先队列 16 } 17 }; 18 char s[maxn]; 19 int pre[maxn], next[maxn]; 20 bool vis[maxn]; 21 priority_queue<node>q; 22 int main() 23 { 24 scanf("%s", s); 25 int n = strlen(s); 26 for(int i = 0; i < n;) 27 { 28 int st = i, len = 1; 29 while(s[++i] == s[st])len++; 30 //cout<<s[st]<<" "<<st<<" "<<len<<endl; 31 q.push(node(s[st], st, len)); 32 } 33 for(int i = 0; i < n; i++) 34 { 35 pre[i] = i - 1, next[i] = i + 1; 36 } 37 memset(vis, 0, sizeof(vis)); 38 while(!q.empty()) 39 { 40 node now = q.top(); 41 q.pop(); 42 if(now.len <= 1)break; 43 if(vis[now.pos])continue; 44 printf("%c", now.c); 45 int head = pre[now.pos], tail = now.pos; 46 for(int i = 0; i < now.len; i++, tail = next[tail]) 47 { 48 vis[tail] = 1; 49 printf(" %d", tail + 1); 50 } 51 puts(""); 52 if(head >= 0)next[head] = tail; 53 if(tail < n)pre[tail] = head; 54 if(head < 0 || tail >= n || s[head] != s[tail])continue; 55 56 int len = 2; 57 while(pre[head] >= 0 && s[pre[head]] == s[head]) 58 head = pre[head], len++; 59 while(next[tail] < n && s[next[tail]] == s[tail]) 60 tail = next[tail], len++; 61 q.push(node(s[head], head, len)); 62 } 63 return 0; 64 }
越努力,越幸运