String Transformation 2 [CF659C][图论][Dp]

文章目录

题目

在这里插入图片描述
CF

思路

妙啊
首先,我们连边 ( a i , b i ) (a_i,b_i) (ai,bi) ,毫无疑问有20个点
在这里插入图片描述
那么一次操作可理解为将某些位置通过边进行一次转移,答案就是边的个数
然后发现可以省略一些边
在这里插入图片描述

换句话说对于一个点 u u u ,设它连接的开始集合点集为 S S S ,只用保证 S S S 中的点 u u u 能通过路径到达即可
但是有时候会有环
在这里插入图片描述

结论:
a n s = 2 ∗ n − S − T ans=2*n-S-T ans=2nST
S S S 表示最大 D A G DAG DAG (可不联通), T T T 表示弱连通图的个数

证明

代码

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int read(){
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
const int MAXN=20;
int fa[MAXN+5];
int Find(int u){return fa[u]==u?u:(fa[u]=Find(fa[u]));}
string s,t;
int f[(1<<MAXN)+5];
int tran[MAXN+5];
void Merge(int u,int v){
	u=Find(u),v=Find(v);
	if(u==v) return ;
	fa[u]=v;
	return ;
}
int main(){//f[s]:s是否为多个DAG
	int T=read();
	while(T--){
		int n=read();
		cin>>s,cin>>t;
		memset(f,0,sizeof(f));
		memset(tran,0,sizeof(tran));
		for(int i=0;i<20;i++)
			fa[i]=i;
		for(int i=0;i<n;i++){
			tran[s[i]-'a']|=(1<<(t[i]-'a'));
			Merge(s[i]-'a',t[i]-'a');
		}
		f[0]=1;
		int ans=40,Ma=0;
		for(int i=0;i<20;i++)
			if(Find(i)==i)
				ans--;
		for(int s=0;s<(1<<20);s++){
			if(!f[s]) continue;
			int cnt=0;
			for(int i=0;i<20;i++){
				if((1<<i)&s)
					cnt++;
				if(tran[i]&s) continue;
				f[s|(1<<i)]=1;
			}
			Ma=max(Ma,cnt);
		}
		printf("%d\n",ans-Ma);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值