好美的图论,真的 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; }