最小割 ---- 集合冲突模型 ---- AGC038 F - Two Permutations[详解]

题目链接


题目大意:

给出两个排列 P , Q P,Q P,Q.要求构造两个排列 A , B . A,B. A,B.
要求: A i Ai Ai要么等于 i i i,要么等于 P i Pi Pi; B i Bi Bi要么等于 i i i,要么等于 Q i Qi Qi
最大化 A i ≠ B i Ai≠Bi Ai=Bi的下标 i i i数量


1e5我都不敢相信这也可以用网络流!!!
这道题看起来无从下手那么我们就分类讨论来看一下
但是发现直接讨论 A i ≠ B i A_i≠B_i Ai=Bi很麻烦,那么问题先变成球最小化 A i = B i A_i=B_i Ai=Bi再用 n n n减掉就好了

  1. P i = Q i = i P_i=Q_i=i Pi=Qi=i 这个时候无论你选什么 A i 一 定 是 等 于 B i A_i一定是等于B_i AiBi
  2. P i = i & & Q i ≠ i P_i=i\&\&Q_i≠i Pi=i&&Qi=i 那么如果 O i = i O_i=i Oi=i的话那么这里就会有1个的相等的位置
  3. Q i = 1 & & P i ≠ i Q_i=1\&\&P_i≠i Qi=1&&Pi=i 那么如果这里 P i = i P_i=i Pi=i的话那么这里就会有1个相等的位置
  4. Q i ≠ P i ≠ i Q_i≠P_i≠i Qi=Pi=i 那么只有 P i = Q i = i P_i=Q_i=i Pi=Qi=i的时候才会有一个相等的位置
  5. Q i = P I ≠ i Q_i=P_I≠i Qi=PI=i那么只要取 P i 和 Q i P_i和Q_i PiQi 或者都取 i i i的时候那么就是有1个相等的位置

但是有一点就是因为 A i 和 B i A_i和B_i AiBi也是全排列!!
注意原题的排列是从0开始的,为讨论方便,我们统一转化为从1开始的。
考虑对于每个排列,把i向Pi连边,那么就会形成很多个环。比如排列 3 , 2 , 4 , 1 {3,2,4,1} 3,2,4,1,其中3,4,1和2分别形成两个环1−3−4−1和2−2。我们令 A i = P i A_i=P_i Ai=Pi,实际上就是把环上的数Pi选转过来(当然理解成把i转过来也可以,只是环上点权设置的问题).。对于一个环,环上的点选择的方案应该是一致的(全都等于i或全都不等于i),否则就会存在某个数不合法


现在我们令两个集合 S , T S,T S,T
对于 P P P数组中的第 i i i个数 P i P_i Pi如果放入S集合里面相当于 A i A_i Ai P i P_i Pi,放入T集合相当于 A i A_i Ai i i i
对于 Q Q Q数组就反过来,如果放入S集合里面相当于 B i B_i Bi i i i,放入T集合相当于 B i B_i Bi Q i Q_i Qi


那么上面的问题就可以转化了
因为是求最小化的位置相同个数!
那么就是最小割,对于每条边我们都赋予割了它的实际意义,那么满足的最小化就是最小割了!!


因为对于同一个轮换里面的位置选的都是一样的那么我们直接用轮换的下标去代替就好了

  1. P i = Q i = i P_i=Q_i=i Pi=Qi=i 这个时候无论你选什么 A i 一 定 是 等 于 B i A_i一定是等于B_i AiBi ans 直接减1
  2. P i = i & & Q i ≠ i P_i=i\&\&Q_i≠i Pi=i&&Qi=i 那么如果 Q i = i Q_i=i Qi=i的话那么这里就会有1个的相等的位置,那么就是 Q i Q_i Qi放到S集合里面代价是1,反过来放在T集合就是代价就是0;
  3. Q i = 1 & & P i ≠ i Q_i=1\&\&P_i≠i Qi=1&&Pi=i 那么如果这里 P i = i P_i=i Pi=i的话那么这里就会有1个相等的位置,同理!
  4. Q i = P I ≠ i Q_i=P_I≠i Qi=PI=i那么只要取 P i 和 Q i P_i和Q_i PiQi 或者都取 i i i的时候那么就是有1个相等的位置,那么按照上的集合划分就是在如果 P i 和 Q i P_i和Q_i PiQi在不同的集合里面代价为1.
  5. Q i ≠ P i ≠ i Q_i≠P_i≠i Qi=Pi=i 那么只有 P i = Q i = i P_i=Q_i=i Pi=Qi=i的时候才会有一个相等的位置,那么就是 P i P_i Pi在S集合里面, Q i Q_i Qi在T集合里面

那么就参考集合冲突模型的建图模型

  1. 直接建图就可以了!!
  2. Q i − > T 流 量 为 1 Q_i->T流量为1 Qi>T1 S − > P i 流 量 为 0 S->P_i流量为0 S>Pi0
  3. Q i − > T 流 量 为 0 Q_i->T流量为0 Qi>T0 S − > P i 流 量 为 1 S->P_i流量为1 S>Pi1
  4. P i − > Q i 流 量 为 1 P_i->Q_i流量为1 Pi>Qi1 Q i − > P i 流 量 为 1 Q_i->P_i流量为1 Qi>Pi1
  5. Q i − > P i 流 量 为 1 Q_i->P_i流量为1 Qi>Pi1

代码:

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)  {
   read(first);
   read(args...);
}
struct node {
   int to, next, len; 
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
   e[cnt] = {to,head[from],len};
   head[from] = cnt ++;
}

int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];

bool bfs() {
   ms(d,0);
   queue<int> q;
   q.push(s); d[s] = 1;
   while(!q.empty()) {
      int u = q.front(); q.pop();
      for(int i = head[u]; ~i; i = e[i].next) {
         int v = e[i].to;
         if(d[v] || e[i].len <= 0) continue;
         q.push(v);
         d[v] = d[u] + 1;
      }

   }      
   for(int i = 0; i <= n; ++ i) cur[i] = head[i];
   return d[t] != 0;
}

int dfs(int u, int flow) {
    if(u == t) return flow;
    for(int &i = cur[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
        int delta = dfs(v,min(flow,e[i].len));
        if(delta <= 0) continue;
        e[i].len -= delta;
        e[i^1].len += delta;
        return delta;
    }
    return 0;
}

int get_maxflow() {
    int maxFlow = 0, delta;
    while(bfs())//bfs进行构建最短路网络
         while(delta = dfs(s,INF))
             maxFlow += delta;
    return maxFlow;
}
int P[maxn], Q[maxn];
int Cle;//统计环的个数
int idp[maxn]; // p数组中每个数在哪个环里面
int idq[maxn]; // q数组中每个数在哪个
int main() {
	IOS;
   ms(head,-1);
   int tn;
   cin >> tn;
   for(int i = 1; i <= tn; ++ i)
      cin >> P[i], P[i] ++;
   for(int i = 1; i <= tn; ++ i)
      cin >> Q[i], Q[i] ++;
   for(int i = 1; i <= tn; ++ i) {
      if(idp[i]) continue;
      Cle ++;
      int idx = i;
      do {
        idp[idx] = Cle;
        idx = P[idx];
      }while(idx != i);
   }
   for(int i = 1; i <= tn; ++ i) {
      if(idq[i]) continue;
      Cle ++;
      int idx = i;
      do {
         idq[idx] = Cle;
         idx = Q[idx]; 
      }while(idx != i);
   }
   int ans = tn;
   s = 0, t = Cle+1;
   n = 2*tn+1;
   for(int i = 1; i <= tn; ++ i) {
      if(P[i] == i && Q[i] == i) ans --;
      else if(P[i] == i) {
         add(idq[i],t,1);
         add(t,idq[i],0);
         //可有可不有
         add(s,idq[i],0);
         add(idq[i],s,0);
      } else if(Q[i] == i) {
         add(s,idp[i],1);
         add(idp[i],s,0);
         //可有可不有
         add(idp[i],t,0);
         add(t,idp[i],0);
      } else if(Q[i] == P[i]) {
         add(idp[i],idq[i],1);
         add(idq[i],idp[i],0);

         add(idq[i],idp[i],1);
         add(idp[i],idq[i],0);
      } else {
         add(idq[i],idp[i],1);
         add(idp[i],idq[i],0);
      }
   }
   cout << ans - get_maxflow();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值