洛谷P9614 [CERC2019] Ponk Warshall
题面分析
题目要求每次交换两个字符,最少多少次交换使第一个字符串变成第二个字符串。
很简单地想到可以凸轮建模,如果一个字符 \(c1\) 要变成另一个字符 \(c2\) 就从 \(c1\) 向 \(c2\) 连有向边,最后再判断环的个数统计答案即可。
关于具体实现
由于只有四种字符,所以建好的图中只有四个节点,用邻接矩阵存即可。
依次判断一元环、二元环、三元环、四元环,它们的花费分别是 0 次、1 次、2 次、3 次。
循环枚举即可。
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6 + 5;
string s,t;
int mp[5][5];
int ans = 0;
int id(char c)
{
if(c == 'A') return 1;
if(c == 'G') return 2;
if(c == 'C') return 3;
if(c == 'T') return 4;
}
signed main()
{
cin >> s >> t;
int len = s.length();
s = ' ' + s;
t = ' ' + t;
for(int i = 1;i <= len;i++) if(s[i] != t[i]) mp[id(s[i])][id(t[i])]++;
for(int i = 1;i <= 4;i++) for(int j = 1;j <= 4;j++)
{
if(mp[i][j] && mp[j][i])
{
int tmp = min(mp[i][j],mp[j][i]);
mp[i][j] -= tmp;
mp[j][i] -= tmp;
ans += tmp;
}
}
for(int i = 1;i <= 4;i++) for(int j = 1;j <= 4;j++) for(int k = 1;k <= 4;k++)
{
if(mp[i][j] && mp[j][k] && mp[k][i])
{
int tmp = min({mp[i][j],mp[j][k],mp[k][i]});
mp[i][j] -= tmp;
mp[j][k] -= tmp;
mp[k][i] -= tmp;
ans += tmp * 2;
}
}
for(int i = 1;i <= 4;i++) for(int j = 1;j <= 4;j++) for(int k = 1;k <= 4;k++) for(int l = 1;l <= 4;l++)
{
if(mp[i][j] && mp[j][k] && mp[k][l] && mp[l][i])
{
int tmp = min({mp[i][j],mp[j][k],mp[k][l],mp[l][i]});
mp[i][j] -= tmp;
mp[j][k] -= tmp;
mp[k][l] -= tmp;
mp[l][i] -= tmp;
ans += tmp * 3;
}
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号