[USACO][DAG上的动态规划]Sorting A Three-Valued Sequence

好美的图论,真的 light up my life!
题意:

给出一个只含有若干1,2,3的数列,我们可以两两交换数列元素;要求输出让这个数列不减的最小交换次数。

思路:

首先看起来很像冒泡.....然鹅要最少交换次数——显然不是模拟冒泡了。

开始用深搜来着,显然没办法剪枝,果断T掉。这个时候就要想一想图论了。

想起来leetcode周赛的1247这道题。题目说的是有两个在{x,y}上相同长度的字符串,我们可以在两个字符串之间任选字符交换。求第一个字符串变成第二个字符串所需要的最小交换次数,有一点点相似~

那道题用的是把原数列和目标状态对比,统计x-y,y-x的个数。a,b都是偶数则恰好交换完(交换次数为 x/2+y/2),ab奇偶不同则无解,ab都是奇数则最后会剩下一堆x-y,y-x,需要额外两次操作(x/2+y/2+2)。

感觉这种*交换都少不了目标态和原态之间对比~这道题也是已知了目标状态,但是是交换自己的字符。也是把当前字符串和目标串比较,就会发现有1-2,1-3,2-1,2-3,3-1,3-2这几种需要处理的情况。这就很像图的边的样子不是嘛!所以我们可以创造一个有向图,顶点为1,2,3,两两顶点都有有向边,边权为对比后算出1-2,2-1这种的数量。这样子,如果1-2和2-1的话就可以直接换掉这两个,交换次数加一。处理完所有重边就可以得到一个没有重边的图,这个图一定是个环,并且环上的边权都相等(因为这是一个必定可解的问题啊)。环是什么意思呢?是要交换两次才能摆平的意思哦~比如1-3,3-2,2-1,就是要把231变成123的意思,需要231->132->123;或者另一个方向的环3-1,1-2,2-3,是把312变成123,需要312->132->123这样。

是不是很巧妙!

代码:

/*
ID :ggy_7781
TASK :sort3
LANG :C++11
*/
#include <bits/stdc++.h>

using namespace std;

int a[1007];
int b[1007];
int N;
int edges[4][4];

int main(void)
{
    freopen("sort3.in","r",stdin);
    freopen("sort3.out","w",stdout);
    cin>>N;
    for(int i =0 ;i < N;i ++)
    {
        cin>>a[i];
        b[i] = a[i];
    }
    sort(b,b+N);

    for(int i = 0;i < N;i ++)
    {
        if(a[i] != b[i])
            edges[a[i]][b[i]] ++;
    }
    int ret = 0;
    for(int i = 1;i <= 3;i ++)
    {
        for(int j = 1;j<= 3;j ++)
        {
            int sub = min(edges[i][j],edges[j][i]);
            ret += sub;
            edges[i][j] -= sub;
            edges[j][i] -= sub;
        }
    }
    ret += 2* (edges[1][3] + edges[3][1]);
    cout<<ret<<endl;

    return 0;
}
上一篇:如何使用forEach循环javascript对对象数组进行排序


下一篇:1028 List Sorting (25分)