洛谷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;
}
posted @ 2025-07-10 17:49  IC0CI  阅读(7)  评论(0)    收藏  举报