第二题:
[编程题] 困兽之斗
经过深思熟虑之后,小贱君打算去M国闯一闯,那是一个古老的东方国度,传说有很多高阶魔法师,他想成为一名伟大的魔法师,将来征服星辰大海。
经过千辛万苦,小贱君终于来到了M国,不幸的是刚进城门小贱君就被M国的守城士兵困在了一种叫做“困兽之斗”的阵法之中。
士兵对小贱君说:“看到漂浮在你身边的宝石了吗?彩虹连接的两颗宝石可以任意交换位置,你需要通过一系列交换后使得宝石组成的字符串的字典序最小。若不能破阵,那还是请回吧!”
小贱君观察了一下周围的宝石,只见每颗宝石上标有一个小写字母,而且有一些宝石上通过彩虹与其他宝石相连。
琢磨了半天,他终于搞懂了这个阵法的意思:
若宝石系列为:dcba
其中有两道彩虹,分别是(0,1),(1,2),代表第一个位置上的宝石可以和第二个位置上的宝石互换,第二个位置上的宝石可以和第三个位置上的宝石互换,最终可以得到字典序最小的宝石系列:bcda。
作为小贱君的死党,你有什么方法帮助他破阵吗?
输入描述:
输入包含多组测试数据。
对于每组测试数据:
字符串s --- 代表宝石序列
n --- 代表有n条彩虹
接下来n行,每行两个数ai,bi --- 表示ai和bi由一条彩虹相连。
保证:
1<=s的长度<=10000
1<=n<=10000
且输入数据均合法。
输出描述:
对于每组数据,输出一个字符串
输入例子:
dcba 2 0 1 1 2 hellonowcoder 4 0 1 1 4 2 5 2 3
输出例子:
bcda ehllonowcoder 思路:并查集 + 排序把能互相连通的字母,进行排序
1 #include<cstdio> 2 #include<cstdlib> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 7 #define N 10005 8 9 using namespace std; 10 11 int n; 12 char s[N]; 13 int f[N]; 14 char ans[N]; 15 int l; 16 17 vector<char> v[N]; 18 vector<int> pos[N]; 19 20 int find(int x){ 21 return x == f[x] ? x : f[x] = find(f[x]); 22 } 23 24 void merge(int a,int b){ 25 int fa,fb; 26 fa = find(a); 27 fb = find(b); 28 if(fa == fb) return; 29 f[fb] = fa; 30 } 31 32 void ini(){ 33 l = strlen(s); 34 scanf("%d",&n); 35 int i; 36 for(i = 0;i < l;i++){ 37 f[i] = i; 38 v[i].clear(); 39 pos[i].clear(); 40 } 41 int a,b; 42 for(i = 1;i <= n;i++){ 43 scanf("%d%d",&a,&b); 44 merge(a,b); 45 } 46 } 47 48 void solve(){ 49 int i,f; 50 for(i = 0;i < l;i++){ 51 f = find(i); 52 pos[f].push_back(i); 53 v[f].push_back(s[i]); 54 } 55 for(i = 0;i < l;i++){ 56 sort(v[i].begin(),v[i].end()); 57 } 58 for(i = 0;i < l;i++){ 59 int sz = pos[i].size(); 60 for(int j = 0;j < sz;j++){ 61 ans[ pos[i][j] ] = v[i][j]; 62 } 63 } 64 ans[l] = ‘\0‘; 65 } 66 67 int main(){ 68 while(scanf("%s",s)!=EOF){ 69 ini(); 70 solve(); 71 printf("%s\n",ans); 72 } 73 return 0; 74 }
第三题:
[编程题]绝域之门
经过多次强攻之后,赫柏带领的军团不仅没能击败鲁卡斯,反而被鲁卡斯打得七零八落,赫柏终于体会到了高阶天之驱逐者的强大实力。
不过,赫柏最终还是找到了鲁卡斯的致命弱点,他发现鲁卡斯喜欢收集上古卷轴,因为上古卷轴能够让鲁卡斯获得神秘之力。
卢卡斯决定使用上古卷轴将卢卡斯引诱到绝域之门,利用绝域之门的力量消灭卢卡斯。
赫柏注意到卢卡斯喜欢收集不同的卷轴,如果总是捡到相同的上古卷轴,它的兴趣就会逐渐降低。
赫柏现在拥有N种不同的卷轴,每种卷轴有Ai个。现在他要将这N个卷轴分散在鲁卡斯领地到绝域之门的路上,每一种排列方式都有一个吸引值Charm,吸引值越高,鲁卡斯被引诱到绝域之门的概率越高。
Charm=Sum of all D(i),其中D(i)=k-i,i为该排列中卷轴i的下标,k为位于i后面且和i是同一种卷轴的卷轴下标。
现在所有的卷轴以<卷轴名称 数量>的格式给出,你需要输出所有卷轴的排列顺序,使得吸引值最大,如果有多种排列方式满足条件,输出按照名字排列字典序最小的一个。
输入描述:
多组测试数据,请处理到文件结束。 对于每组测试数据: 第一行:一个整数N,代表有N种卷轴。 第二行:N种卷轴的描述。 保证: 0<=N<=50; 卷轴名称为长度1~10的字母,每种卷轴的数量为1~800之间的一个整数。
输出描述:
输出所有卷轴的一个排列。
输入例子:
3 Thunder 1 Wind 3 Soil 2
输出例子:
Soil Wind Thunder Wind Soil Wind
题解转自:
每种字符串的吸引值只与它第一次出现和最后一次出现的位置有关,所以我们可以先把所有字符串的首尾出现位置确定,再把其余的字符串塞到中间就行了,安排字符串位置时均按照字典序由小到大的顺序。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<vector> 5 #include<cstring> 6 #include<algorithm> 7 8 #define N 55 9 10 using namespace std; 11 12 struct PP{ 13 string s; 14 int count; 15 }A[N]; 16 17 bool cmp(PP a,PP b){ 18 return a.s < b.s; 19 } 20 21 int n; 22 string ans; 23 string l,r,mid; 24 25 void ini(){ 26 ans = l = r = mid = ""; 27 int i; 28 for(i = 0;i < n;i++){ 29 cin >> A[i].s >> A[i].count; 30 } 31 } 32 33 void solve(){ 34 sort(A , A + n,cmp); 35 int i; 36 for(i = 0;i < n;i++){ 37 if(A[i].count > 1){ 38 l += A[i].s + ‘ ‘; 39 r += A[i].s + ‘ ‘; 40 A[i].count -= 2; 41 } 42 } 43 for(i = 0;i < n;i++){ 44 while(A[i].count >= 1){ 45 mid += A[i].s + ‘ ‘; 46 A[i].count --; 47 } 48 } 49 ans = l + mid + r; 50 if(ans.size() >= 1){ 51 ans.pop_back(); 52 } 53 } 54 55 int main(){ 56 while(scanf("%d",&n)!=EOF){ 57 ini(); 58 solve(); 59 cout<<ans<<endl; 60 } 61 return 0; 62 }