关于匹配方向
  • 板块CF1728F Fishermen
  • 楼主HYLW
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/8/7 19:59
  • 上次更新2024/8/7 20:54:33
查看原帖
关于匹配方向
663949
HYLW楼主2024/8/7 19:59

以下有两段代码,在第一段中,我将建边设为从 aa 数组(离散后的编号)到对应数据的倍数(离散后的编号),这无法通过题目。

但是在第二段代码中,我将建边方向反向,即由对应数据倍数(离散后的编号)到 aa 数组(离散后的编号),这样通过了题解。

同机房的大佬说是正着(aa 指向其倍数)存在匹配失败的问题,但是显然,既然反着(aa 的倍数指向 aa )匹配可以成功,那么正着也因该存在成功情况,这不是匹配失败的可接受理由。

仅仅只是建边方向的不同,为什么结果不一样?

第一段代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1010,M = N*N;
int a[N],n;//如题目所述 
vector<int> b;//离散化 

int h[N],e[M],ne[M],idx;
void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}//建边 

unordered_map<int,int> id;//离散化 

int mat[M],mbt[N];//双向匹配 

bool s[M];//与访问vis数组等价 

bool dfs(int u){//匈牙利算法 
	for(int i=h[u],v;~i;i=ne[i]){
		v=e[i];
		if(s[v])	continue;
		s[v]=true;
		if(mat[v]==0 || dfs(mat[v])){
			mat[v]=u;
			mbt[u]=v;//双向匹配 
			return true;
		}
	}
	return false;
}

ll ans;
int main(){
	memset(h,-1,sizeof h);
	b.push_back(-1);//init,垫一个,方便后续下标访问 
	
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		for(int k=1;k<=n;k++)
			b.push_back(a[i]*k);
	}
	
	sort(b.begin(),b.end());
	b.erase(unique(b.begin(),b.end()),b.end());
	for(int i=1;i<b.size();i++)//从下标1开始,上面垫了一个 
		id[b[i]]=i;
	//离散化 
	for(int i=1;i<=n;i++)
		for(int k=n;k>=1;k--)
			add(i,id[a[i]*k]);//正着建边 
	
	for(int i=n;i>=1;i--){
		memset(s,false,sizeof s);
		dfs(i);
	}
	
	for(int i=1;i<=n;i++)	ans+=b[mbt[i]];//双向匹配的原因 
	
	printf("%lld",ans);
	return 0;
}

第二段代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1010000,M = N;
int a[N],n;
vector<int> b;

int h[M],e[M],ne[M],idx;
void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

unordered_map<int,int> id;

int mat[M],mbt[N];

bool s[M];

bool dfs(int u){
	for(int i=h[u],v;~i;i=ne[i]){
		v=e[i];
		if(s[v])	continue;
		s[v]=true;
		if(mat[v]==0 || dfs(mat[v])){
			mat[v]=u;
			mbt[u]=v;
			return true;
		}
	}
	return false;
}

ll ans;

int main(){
	memset(h,-1,sizeof h);
	b.push_back(-1);
	
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		for(int k=1;k<=n;k++)
			b.push_back(a[i]*k);
	}
	
	sort(b.begin(),b.end());
	b.erase(unique(b.begin(),b.end()),b.end());
	for(int i=1;i<b.size();i++)	id[b[i]]=i;
	
	for(int i=n;i>=1;i--)
		for(int k=n;k>=1;k--)
			add(id[a[i]*k],i);//反着建边 
	
	int cnt=0;
	for(int i=0;i<b.size();i++){
		if(dfs(i)){
			ans+=b[i];
			memset(s,false,sizeof s);//一点优化,不足挂齿 
			cnt++;
			if(cnt==n)	break;//新的判定方式 
		}
	}
	printf("%lld",ans);
	return 0;
}
2024/8/7 19:59
加载中...